Data gets truncated in SAP RFC - abap

I have a big string containing 400 MByte JSON data in rfc function module.
See debugger:
Unfortunately my pyRFC client only receives roughly 34 MByte.
Where and why does my data get cut?
Is this a well known limitation of sap-rfc?
Strange but true, I already transferred json strings with 77 MByte successfully.
Related issue at github: https://github.com/SAP/PyRFC/issues/97

It cannot be a limitation of SAP RFC. I have made a simple test. I created an RFC function module in one of the systems (let us name the RFC destination for it DEV000). It looks like this.
FUNCTION Z_TEST .
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*" EXPORTING
*" VALUE(E_STRING) TYPE STRING
*"----------------------------------------------------------------------
e_string = `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`.
DO 23 TIMES.
e_string = e_string && e_string.
ENDDO.
ENDFUNCTION.
Then I wrote a simple program in another system that calls this function module.
REPORT ZZZ.
DATA: g_string TYPE string.
CALL FUNCTION `Z_TEST`
DESTINATION `DEV000`
IMPORTING
e_string = g_string.
BREAK-POINT.
The string gets transferred in full, so it cannot be a limitation of SAP RFC. I guess you have to search for the cause rather in your pyRFC library or in your Python's client code.

Related

Does ABAP CALL statement set SY-SUBRC value?

I'm looking at the description of CALL - System Function Call in the SAP ABAP Keyword Definition. Such calls have the format CALL 'xxx' ID 'yyy' FIELD 'zzz'. The ABAP Keyword Definition does not mention that sy-subrc is set by calling a system function. But somehow, I suspect that it is.
Can I "trust" the Keyword Definition in such a case? (sy-subrc not mentioned => not set)
What would be a "good" example system function call to test it on an SAP system? (does not break/change anything, exists on all systems)
Note that I'm not an ABAP programmer and I usually handle third-party ABAP programs in Java as text / parse tree. I know that one usually should not call system functions, but the ABAP code I look at might have such calls. Furthermore, I'm not interested in the actual value a specific system call sets sy-subrc to, just in the fact whether system calls set/alter sy-subrc or not.
Well, as you are asking this question you are already aware this is NOT recommended approach to use direct SYSTEM calls. However, if you still want to use them...
By using CALL statement SAP kernel C-modules are called and without knowing the source we can not interpret the returning value confidently, either it's 0 or 1.
Despite there are examples (see line 230 of DYNP_VALUES_READ FM) where sy-subrc value is checked after system calls, nobody except SAP knows which value to check in certain case. Nor we.
Also there were reports (1, 2) about ambiguous meaning of these values during tests.
So the answer is NO, sy-subrc in this context brings no meaningful information.
P.S. Answering your questions:
No, you cannot interpret it that way. If something is not mentioned in ABAP Documentation then this not known for sure or not meaningful at all.
I cannot confirm this is good idea at all (to test system calls), but if you want you can try call SYSTEM function.
It calls arbitrary Unix command. For example, you can move files stored on your ABAP Server like this:
CALL 'SYSTEM'
ID 'COMMAND'
FIELD 'mv /usr/sap/temporary
/usr/sap/definite'.
Now this should be a safe call that works on any system:
DATA: dbserver TYPE char255.
CALL 'C_SAPGPARAM' ID 'NAME' FIELD 'SAPDBHOST'
ID 'VALUE' FIELD dbserver.
As you probably already know there are some exceptions that can occur. As for sy-subrc, when a command sets sy-subrc it is usually explicitly mentioned in the documentation including which values it can hold and their meaning. But don't quote me on that.
Simple (harmless) function modules are RH_GET_DATE_DAYNAME that requires the language and 10 character date (eg. 26.10.2016) as input fields and DATE_TO_DAY that only requires the 10 character date as input. The sy-subrc should be returned as 0 if a valid date is entered.

Material Ledger consistency check function module

Is there a function module or BAPI or method that nicely performs a material/material ledger consistency check for a given material?
I am aware of report SAPRCKMU which would be very hard to use inside my own program.
I am also aware of and using function module CKML_F_CKML1_PRICES_GET which performs a consistency check.
When this function module finds an inconsistency, it calls MESSAGE E... which means I lose control in my program. This is the core problem that I have.
So I am searching a way to check consistency before I call CKML_F_CKML1_PRICES_GET in a way that gives me a return parameter with the error message without calling MESSAGE E....
I found a solution that works very well:
add the line error_message = 99 to the function module call:
CALL FUNCTION 'CKML_F_CKML1_PRICES_GET'
....
EXCEPTIONS
...
error_message = 99
others = 98.
Now the program doesn't interrupt the control flow when the function module itself uses MESSAGE E... instead of RAISE ....
Whenever MESSAGE E... is called inside, it is converted into SY-SUBRC = 99 and the error-fields in SY-... are also set.

How to load DLL file from Jscript file?

So I'm writing a standalone JScript file to be executed by Windows Script Host (this file is not going to be used as a web application).
My goal is to load a dll file. Just like using LoadLibrary function in a C++ application.
I tried researching the subject but I didn't come up with anything useful. I'm so lost I don't have any piece of code to share. I understand using ActiveXObject may come to my rescue. if so, any idea how to use it?
Update:
If we all agree that loading is impossible, I'll settle for validity check. Meaning, don't try to load but check if it is loaded and functional.
You can export a specific function for this purpose.
Then, from your JScript, execute rundll32.exe and check that the function ran as expected.
You might also give Gilles Laurent's DynaWrap
ocx a chance.
This kind of dll needs to be registered on the target system like regsvr32 /s DynaWrap.dll.
It is restricted to 32-bit DLLs, and this might be inconvenient for you to use, but it works on a 64bit Windows. You can't access function exported by ordinal number and you can't directly handle 64bit or greater values/pointers.
Here's a sample to call MessageBoxA from JScript:
var oDynaWrap = new ActiveXObject( "DynamicWrapper" )
// to call MessageBoxA(), first register the API function
oDynaWrap.Register( "USER32.DLL", "MessageBoxA", "I=HsSu", "f=s", "R=l" )
// now call the function
oDynaWrap.MessageBoxA( null, "MessageBoxA()", "A messagebox from JScript...", 3 )
And here from VBScript:
Option Explicit
Dim oDynaWrap
Set oDynaWrap = CreateObject( "DynamicWrapper" )
' to call MessageBoxA(), first register the API function
UserWrap.Register "USER32.DLL", "MessageBoxA", "I=HsSu", "f=s", "R=l"
' now call the function
UserWrap.MessageBoxA Null, "MessageBoxA()", "A messagebox from VBScript...", 3
To use a function you need to "register" the exported function of your DLL.
To do this you need to call the register method with a first parameter containing a string object to the complete path of the DLL, a second parameter for the exported name of the function to use, and following three paremeters describing the functions declartion in a somehow obscure syntax.
i= describes the number and data type of the functions parameters.
f= describes the type of call: _stdcall or _cdecl. Default to _stdcall.
r= describes the return values data type.
The supported data types are:
Code Variant Description
a VT_DISPATCH IDispatch*
b VT_BOOL BOOL
c VT_I4 unsigned char
d VT_R8 8 byte real
f VT_R4 4 byte real
h VT_I4 HANDLE
k VT_UNKNOWN IUnknown*
l VT_I4 LONG
p VT_PTR pointer
r VT_LPSTR string by reference
s VT_LPSTR string
t VT_I2 SHORT
u VT_UINT UINT
w VT_LPWSTR wide string
Thus the Register method call used in the examples describes MessageBoxA like this:
_stdcall LONG MessageBoxA( HANDLE, LPSTR, LPSTR, UINT );
For a explanation of MessageBoxA look at the docs on MSDN.
Please read the DynaWrap docs for more sophisticated examples... But you might need Google translate, 'cos they are written in french ;-)
To be able to use a dll as ActiveXObject, it needs to be registered as COM object. There are some restrictions on this but if you have a code for this dll, it is certainly doable.
When you register your dll as COM object, it is assigned a name. You use this name to create an object. This example from MSDN uses excel since it is already registered if you installed office.
var ExcelApp = new ActiveXObject("Excel.Application");
var ExcelSheet = new ActiveXObject("Excel.Sheet");
// Make Excel visible through the Application object.
ExcelSheet.Application.Visible = true;
// Place some text in the first cell of the sheet.
ExcelSheet.ActiveSheet.Cells(1,1).Value = "This is column A, row 1";
// Save the sheet.
ExcelSheet.SaveAs("C:\\TEST.XLS");
// Close Excel with the Quit method on the Application object.
ExcelSheet.Application.Quit();
Apart from restriction of registering dll, using dll is no different from using it as c++ or c# dll. Note that, C# (or other .NET dlls) should be ComVisible to be used from javascript this way.
EDIT: The only other way of using C/C++ dll from javascript is swig interfaces. I have not used it, therefore I can only point you in that direction.
SWIG is a software development tool that connects programs written in
C and C++ with a variety of high-level programming languages. SWIG is
used with different types of target languages including common
scripting languages such as Javascript, Perl, PHP, Python, Tcl and
Ruby.

Handling message classes defined on another system

When working with RFC-enabled Function Modules I often add custom return messages. These are defined as message classes with IDs and parameters. Now I receive those messages perfectly in my calling program, but since the caller can be on a different system the message classes I defined on the source system are unknown. Standard output of these messages to a message manager or application log fails as the text can't be generated.
What is the best practice for making these types of messages meaningful in the calling environment?
Is there an alternative to filling the text field in the source program, for instance by using MESSAGE_TEXT_BUILD? If I fill that text will standard SAP code not try to overwrite it from a non-existent message class?
Best option I can think of is to make your own RFC function module that takes in a message id, number, etc and returns a message string. You will have to distribute this to all the systems. You code it as:
FUNCTION zget_message.
*"----------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" REFERENCE(i_msgid) TYPE msgid
*" REFERENCE(i_msgno) TYPE msgno
*" REFERENCE(i_msgv1) TYPE msgv1
*" REFERENCE(i_msgv2) TYPE msgv1
*" REFERENCE(i_msgv3) TYPE msgv1
*" REFERENCE(i_msgv4) TYPE msgv1
*" EXPORTING
*" VALUE(e_message) TYPE string
*"----------------------------------------------------------------------
MESSAGE ID i_msgid TYPE 'I' NUMBER i_msgno
WITH i_msgv1 i_msgv2 i_msgv3 i_msgv4
INTO e_message.
ENDFUNCTION.
There is probably a SAP standard RFC that does this somewhere but I don't know what it is.
As far as i know, You should be informed,or it should be defined and documented, which messages a remote caller can use inside the remote system, so that the calling app just gets them back to show them. In terms of classes, which interfer on both systems, I do not know anything, that would prevent collisions/missing id's/classes. So You for Yourself will have to deal with that.
No, I researched, there is definetely no way to deal with that, You as developer should be aware, that any remote assigned messages are NOT used locally.

RFC for remote call transaction

How do I call the SAP report (for example RSPARAM) with help JCo?
What RFC may be used to remotely call SA38 transaction with RSPARAM (e.t.c.) as parameter and then return results for later work ?
RFC is for calling function modules, not programs. It's possible to use some generic function module to start a report, but since you'll usually want to process the results of the program and the program does not know that it was meant to deliver its results in a machine-readable way, you probably won't get too far this was. What exactly are you trying to do?
With the nearly infinite possible results of calling a transaction, i don't think there is a RFC to execute such an operation and return a result. What would be the result in case of an ALV display, or if the program then wait for some interactions ?
You can display a transaction in SAP portal using transactions Iviews. You're then using the portal page as a HTMLGui for your transaction.
also, some FM can sometime be used to perform operations instead of a full program (ie HR_INFOTYPE_OPERATION instead of pa30).
regards
Guillaume
Edition : since you want the result of RRSPARAM, you could encapsulate the "important" part (form SHOW_ACTUAL_PAR_VALUES_ALV) in a module function accessible by RFC, and returning a table of CST_RSPFPAR_ALV (ie the same structure that is displayed in the report)
regards
If You don't find a function to call, just create one by yourself. Tag it as callable from outside via RFC and in the coding, perform such things as "submit report xyz with param1 = value1 ... and return ... exporting list to memory". Then you can even return list output from this. Define the interface of the freshly created function module as you need (that means, report name as input, list output as a table of strings, e.g.). Attention, there is of course a big security risk, having an remote function accepting variable reportnames. But I am sure You know :-)