With the help of the QSQCHKS API, you can easily and quickly find where errors occur.
A lot of people run SQL statements often, but few of them can find the place where an error occurs in those statements. In this article, I'll show you how to detect the position of these errors by using the Syntax Check SQL Statement (QSQCHKS) API , which is documented here.
Several years ago, I discovered this API, but there was no example of how to use it. Later, I discovered one curious undocumented feature that was not described in the API documentation. So today I decided to share this information with you.
According to IBM documentation, this API uses an internal parser that can scan the string of the SQL statement, using Interactive SQL syntax rules or rules of the language you specify. The result will show the column and row error position in the SQL statement string along with some additional information.
The sample program below shows how to use this API. Note that I used comments in certain blocks of my code. Later in this article, I will explain in detail. My code is divided into two parts: definitions of some structures for this API and the code for using it. I kept this code as it was written many years ago when there was no free-format source.
* ---- Definitions
D vSTMT S 16322A
D Stmt DS QUALIFIED
D Len 10I 0
D NumRec 10I 0 INZ(1)
D Lang 10A INZ('*NONE')
D inSize 10I 0 INZ(%size(QSQ_Stmt))
D nRec 10I 0
DQSQ_Options DS QUALIFIED
D NumKeys 10I 0 INZ(1)
D key01 10I 0 INZ(1)
D key01len 10I 0 INZ(10)
D key01data 10A INZ('*SYS')
DQSQ_Stmt DS QUALIFIED
D MsgfName 1 10
D MsgfLib 11 20
D NumStmts 21 24B 0
D StmtI likeDS(StmtT)
DStmtT DS QUALIFIED
D lenStmt 1 4B 0
D rowBegin 5 8B 0
D colBegin 9 12B 0
D rowEnd 13 16B 0
D colEnd 17 20B 0
D rowErr 21 24B 0
D colErr 25 28B 0
D msgID 29 35
D state 36 40
D lenMsg 41 44B 0
D msgData 45 145A
DQUSEC DS 116 INZ
D QUSBPRV 1 4B 0 Bytes Provided
D QUSBAVL 5 8B 0 Bytes Available
D QUSEI 9 15 Exception Id
D QUSERVED 16 16 Reserved
D QUSMSGDTA 17 116 Message Data
*--- Temporary variable -----------------------
D s80 S 80A
*------------------------------
* Checking of the SQL statement
C cSQL#sr BEGsr
* 1) Syntax Check SQL Statement
* 1-1) Initialization
C Eval Stmt.Len = %len(%trimr(vSTMT))
*>> unexpected change ------------------------------
C Stmt.Len IFlt 80 IF1
C Z-add 80 Stmt.Len
C ENDif ENDif1
*--------------------------------------------------
C MOVE *BLANK QUSEI
* 1-2) The Len must be greater than *ZERO
C Stmt.Len IFle *ZERO IF2
C Eval s80 = 'The local statement is empty'
C LEAVEsr
C ENDif ENDif2
* 1-3) Run api
C CALL 'QSQCHKS' 98
C PARM vSTMT In>Statement
C PARM Stmt.Len In>Len
C PARM Stmt.NumRec In>
C PARM Stmt.Lang In>
C PARM QSQ_Options In>
C PARM QSQ_Stmt Out>DS result
C PARM Stmt.inSize In>size DS
C PARM Stmt.nRec Out>num records
C PARM QUSEC Out>Error
* 1-4) And the result
C SELECT SELECT1
* - External error
C *In98 WHENeq *ON
C LEAVEsr
* - Api Error
C QUSEI WHENne *BLANK
* ... Retrieve msg from QCPFMSG *msgf using
* QUSEI and QUSMSGDTA
C LEAVEsr
* - SQL Error
C WHEN QSQ_Stmt.StmtI.msgID <> *BLANK
* ... Retrieve msg from QSQLMSG *msgf using
* QSQ_Stmt.StmtI.msgID and QSQ_Stmt.StmtI.msgData
C IF QSQ_Stmt.StmtI.colErr > *ZERO IF3
... Here is the error position
C ENDif ENDif3
C LEAVEsr
C ENDsl ENDsl1
C ENDsr
In the middle of the code, you see the call to the QSQCHKS API. The first and second parameters are the SQL statement string and its length. The third parameter is the number of records—in our case, it's 1. If you want to use standard SQL rules for checking, you can set the fourth parameter to '*NONE'. The fifth parameter is settings. I set it because I wanted to add a key for that condition according to the API documentation: '*SYS - Table names are qualified using the system naming convention in the form library/table.' The sixth and seventh parameters are the resulting data structure and its size. The last two parameters are the number of records processed (usually one) and the standard error structure.
I added this block: <<unexpected change because in some cases this API returns error SQL0901: 'Record length parameter not valid'. The solution is simply to add this block to avoid unexpected problems when the Stmt.Len is between 1 and 79 and the SQL statement is completely correct in grammatical rules but this error occurs.
This block has some history. The first time I received SQL0901, I didn't understand what it meant. The API was called several times with no error, but then suddenly the error occurred. I went deep into the Internet and found out that there was a PTF to resolve the issue of SQL construction failing with SQL0901. So I thought that there had to be something in the IBM documentation that would help to explain. And I read the QSQCHKS documentation again from V3R1 till now. I found interesting information: "{Left,Right} margin. The {left,right} margin for the source. This parameter is only valid if language is PL/I or C and the valid values are from 1 to 80." So I guessed that somewhere deep in QSQCHKS there's mention of margin 80. With debug, I checked it and discovered that Stmt.Len needs to be greater than 80 in order to avoid exception error SQL0901.
I hope that this information helps you avoid errors when you use this API!
LATEST COMMENTS
MC Press Online