Issue using yajl_saveBuf

Discussions relating to the ScottKlement.com port of the open source YAJL JSON Reader/Generator. This includes the YAJL tool as well as the YAJLR4, YAJLGEN, YAJLINTO and YAJLDTAGEN add-ons from ScottKlement.com. http://www.scottklement.com/yajl/
tbrantley
Posts: 9
Joined: Fri Jul 14, 2023 9:25 pm

Issue using yajl_saveBuf

Post by tbrantley »

Good afternoon!

I'm new to using the YAJL functions.

I'm getting a compile error after I add yajl_saveBuf function to my program. Program compiles successfully until I add this one line of code.

yajl_saveBuf('/temp/example.json': errMsg);

What am I missing here? Do I need to add another library?

Thanks,
Trent
Scott Klement
Site Admin
Posts: 658
Joined: Sun Jul 04, 2021 5:12 am

Re: Issue using yajl_saveBuf

Post by Scott Klement »

What error do you receive?
tbrantley
Posts: 9
Joined: Fri Jul 14, 2023 9:25 pm

Re: Issue using yajl_saveBuf

Post by tbrantley »

I figured it out Scott! I didn't realize that the parms had to be defined the exact same way.

I'm now able to successfully write Json created with YAJL functions to IFS directory.

Thanks,
Trent
tbrantley
Posts: 9
Joined: Fri Jul 14, 2023 9:25 pm

Re: Issue using yajl_saveBuf

Post by tbrantley »

Scott,

I'm having trouble getting the yajl_copyBuf function to work. I've pasted some of my code below.

Do you see anything wrong with what I'm doing? Just to verify that the buffer was getting populated I tried using the yajl_copyBufStr and it works correctly.

dcl-proc Get_Buffer_Data;

dcl-s JSONDataLength int(10);
dcl-c ToCCSID const(37);
dcl-s jsonData varchar(32000);

yajl_copyBuf( ToCCSID: %addr(jsonData: *Data):
%size(jsonData): JSONDataLength);

jsonData = yajl_copyBufStr();

return;
end-proc Get_Buffer_Data;
Scott Klement
Site Admin
Posts: 658
Joined: Sun Jul 04, 2021 5:12 am

Re: Issue using yajl_saveBuf

Post by Scott Klement »

Is there a reason you need to use yajl_copyBuf() instead of yajl_copyBufStr()?

The obvious problem with your yajl_copyBuf code (or at least the part you've provided) is that you aren't bothering to set the length of the buffer, and you're providing an incorrect length to the routine.

Pointer and raw memory techniques do require a little bit more knowledge and understanding of how the computer works. That's why I provided yajl_copyBufStr(), so you don't need to worry about that stuff.
Scott Klement
Site Admin
Posts: 658
Joined: Sun Jul 04, 2021 5:12 am

Re: Issue using yajl_saveBuf

Post by Scott Klement »

Code: Select all

%len(jsonData) = %len(jsonData:*max);   <-- set the length of the varchar to its maximum size
yajl_copyBuf( ToCCSID: %addr(jsonData: *Data): %len(jsonData): JSONDataLength);  <-- use the max length (not %size)
%len(jsonData) = JSONDataLength;   <-- set the length of the VARCHAR to the length in the buffer
Or, better:

Code: Select all

jsonData = yajl_copyBufStr();
tbrantley
Posts: 9
Joined: Fri Jul 14, 2023 9:25 pm

Re: Issue using yajl_saveBuf

Post by tbrantley »

Scott,

My goal was to hopefully be able to use the data from the buffer in SQL/HTTP functions.

SQL Webservices has a 32k variable size limit as far as I can tell.

I would like to send more than 32k when using the HTTP post function.

EXEC SQL
SELECT RESPONSE_MESSAGE, RESPONSE_HTTP_HEADER
INTO :rspData, :rspHdr
FROM TABLE(QSYS2.HTTP_POST_VERBOSE(
CAST(trim(:myUrl) AS VARCHAR(500)),
CAST(trim(:jsonData) AS VARCHAR(32000)),
CAST(trim(:myHdr) AS VARCHAR(5000))));

Hopefully that makes sense.
Scott Klement
Site Admin
Posts: 658
Joined: Sun Jul 04, 2021 5:12 am

Re: Issue using yajl_saveBuf

Post by Scott Klement »

Trent,

yajl_copyBufStr() allows up to 2 million characters. (Granted, yajl_copyBuf can allow much more -- but... that's a far cry from 32k!!)

HTTP_POST_VERBOSE allows for up to 2 gigabytes -- which is almost much more than 32k -- BUT, you appear to be declaring your field as VARCHAR. VARCHAR in RPG (and therefore with YAJL or HTTPAPI) can be up to 16mb in size. But SQL only allows VARCHAR to be 32k, because SQL expects the VARCHAR to be a column in a row (aka field in a record) and therefore needs to be relatively small. SQL is designed for databases, after all.

To allow larger values, SQL has "large object support", aka LOBs. In this case, it'd be a character LOB (aka CLOB) that you need to use for larger values. So you'll have to decare and populate your RPG variable as a CLOB (or stop using SQL for HTTP -- and use something else like HTTPAPI)

This has nothing whatsoever to do with YAJL -- it's about how SQL works.
tbrantley
Posts: 9
Joined: Fri Jul 14, 2023 9:25 pm

Re: Issue using yajl_saveBuf

Post by tbrantley »

Scott,

I really appreciate your help! I've got one more question for ya!

I'm moving the data from the copyBufStr function into a clob variable.

Once I try to use the clob variable inside the SQL statement I get the error below.

Length in varying-length, LOB, or XML host variable not valid.

Cause . . . . . : Host variable JSONDATA was specified. The value in the
length portion of the variable length, LOB, or XML host variable is either
negative or greater than the declared length. If the host variable is
graphic the length should be the number of DBCS characters. The host
variable number is 2. The specified length is -1065379967. The variable is
declared to have length 100000.

Recovery . . . : Change the length portion of the varying-length, LOB, or
XML host variable to a valid positive number or zero. Try the request again.

dcl-s jsonData SQLTYPE(CLOB:100000) inz;

jsonData = yajl_copyBufStr();

EXEC SQL
SELECT RESPONSE_MESSAGE, RESPONSE_HTTP_HEADER
INTO :rspData, :rspHdr
FROM TABLE(QSYS2.HTTP_POST_VERBOSE(
CAST(trim(:myUrl) AS VARCHAR(500)),
CAST(trim(:jsonData) AS CLOB(100000)),
CAST(trim(:myHdr) AS VARCHAR(2000))));
Scott Klement
Site Admin
Posts: 658
Joined: Sun Jul 04, 2021 5:12 am

Re: Issue using yajl_saveBuf

Post by Scott Klement »

When you use SQLTYPE(CLOB:100000) (as you did), the SQL precompiler will generate an RPG data structure under the covers. So if you look at the code it generated (for example, in the compile listing) you'll see something like this:

Code: Select all

  DCL-DS JSONDATA;
    JSONDATA_LEN   UNS(10);
    JSONDATA_DATA  CHAR(100000);
  END-DS;
So you need to set two fields to populate the CLOB, not just one...

Code: Select all

jsonData_data = yajl_copyBufStr();
jsonData_Len  %len(%trimr(jsonData_data));
That's the way the SQL precompiler works (which, imho, is kinda clumsy -- but, hard to change it at this point, too many people are using it.)
Post Reply