10-04-2012 11:17 AM
Hi,
I have written a function module that does a query on a table.
The function modules takes range tables in input (sign, op, low, high) for every field of the table, performs the SELECT and then outputs its results.
I have used as the inputs' data type a generic range table type SEL_OBJT whose LOW and HIGH fields are CHAR(180).
The table on which I extract the data has several fields whose types are CHAR(16), CURR(13,2), DATS(8), TIMS(6).
Now, since this function module will be exposed as a webservice, I'm expecting that the LOW and HIGH fields of the input tables will be rendered as the generic java type String (unlimited number of characters) and that hence the consumer could send me invalid data: e.g., he could write "TEST" for the Currency field instead of a number or he could send me a 30 character string for the field whose maximum length is 16.
I've not yet generated the webservice and now I'm only testing the function module locally.
If I try to populate the range table with invalid values, I get a dump.
How can I perform an input check in the function module to be sure that all the fields are of the correct type (i.e. CHAR(16), CURR(13,2), DATS(8) and TIMS(6))? My goal is to avoid a dump and to be able to tell the caller what field was wrong.
I've used generic range tables because I thought that all the fields would be rendered as String when exposed as Web Service and so I didn't bother to create custom range table types. Am I wrong in doing that? Could using proper range table types avoid the problem in the first place?
Thank you.
10-04-2012 12:28 PM
For your selection parameters you could use a TRY/MOVE/ENDTRY catching exceptions like CX_SY_CONVERSION_NO_NUMBER, CX_SY_CONVERSION_OVERFLOW.
Code could look like:
LOOP AT parameter_list.assigning <parameter>.
* (...)
CREATE DATA dref type(typename).
ASSIGN dref->* TO <fs>.
TRY.
MOVE <parameter>-value(len) to <fs>.
CATCH CX_SY_CONVERSION_NO_NUMBER.
* etc.
* (...)
CREATE DATA dref type(<parameter>-typename;
Then you could also use a TRY/SELECT/ENDTRY to read the data from database, catching exceptions like CX_SY_OPEN_SQL_DB, CX_SY_DYNAMIC_OSQL_SEMANTICS and CX_SY_DYNAMIC_OSQL_SYNTAX
Look at ABAP online documentation (and test thoroughly) your module to find other exceptions. If some are Non-Catchable exceptions, you will have to code yourself some checks depending on the target type of data.
Regards,
Raymond
10-04-2012 11:47 AM
If you are exposing your FM as a webservice, suggested way to have import/export parameter as string only. Then you can validate the input inside your code and convert it if necessary to any range or whatever or raise proper message as response for the webservice.
10-04-2012 12:28 PM
For your selection parameters you could use a TRY/MOVE/ENDTRY catching exceptions like CX_SY_CONVERSION_NO_NUMBER, CX_SY_CONVERSION_OVERFLOW.
Code could look like:
LOOP AT parameter_list.assigning <parameter>.
* (...)
CREATE DATA dref type(typename).
ASSIGN dref->* TO <fs>.
TRY.
MOVE <parameter>-value(len) to <fs>.
CATCH CX_SY_CONVERSION_NO_NUMBER.
* etc.
* (...)
CREATE DATA dref type(<parameter>-typename;
Then you could also use a TRY/SELECT/ENDTRY to read the data from database, catching exceptions like CX_SY_OPEN_SQL_DB, CX_SY_DYNAMIC_OSQL_SEMANTICS and CX_SY_DYNAMIC_OSQL_SYNTAX
Look at ABAP online documentation (and test thoroughly) your module to find other exceptions. If some are Non-Catchable exceptions, you will have to code yourself some checks depending on the target type of data.
Regards,
Raymond
10-04-2012 1:50 PM
Could there be a way to do a dynamic check on all the Function Module's import parameters?
I'm no ABAP expert but I was thinking something like this:
DATA : ls_fm_interface TYPE rsfbintfv,
lt_fm_import TYPE rsfb_para,
ls_fm_import TYPE rsfbpara.
DATA : d_import TYPE REF TO data.
FIELD-SYMBOLS : <fs>.
CALL METHOD cl_fb_function_utility=>meth_get_interface
EXPORTING
im_name = 'Z_MY_FUNCTION_MODULE_NAME'
im_mode = 'DISPLAY'
im_active = 'A'
* im_read = 'J'
IMPORTING
ex_interface = ls_fm_interface
* EXCEPTIONS
* error_occured = 1
* object_not_existing = 2
* others = 3
.
MOVE ls_fm_interface-import TO lt_fm_import.
LOOP AT lt_fm_import INTO ls_fm_import.
IF ( ls_fm_import-typefield NE 'SEL_OBJT' ).
EXIT.
ENDIF.
CREATE DATA d_import TYPE Z_MY_TABLE_NAME-(ls_fm_import-parameter).
ASSIGN d_import TO <fs>.
TRY.
" Check the parameter
CATCH cx_sy_conversion_no_number.
ENDTRY.
ENDLOOP.
This code obviously doesn't compile. The problem is that I don't know:
Can you help me on that?
Is this overkill? (I didn't want to replicate code by cut and paste and if there's a way to do something dynamically I prefer doing that that way).
Thanks again!