Dynamic SQL and Setting SQLCODE
Is there a reason why calling %ExecDirect() (or %Execute) won't set the %SQLCODE of the result set to 100 even when the query returns no data?
Here is the code in question with a bit of contrivance to force the issue:
set statement = ##class(%SQL.Statement).%New()
set result = ##class(%SQL.Statement).%ExecDirect(statement,"select top 0 0 from Example.Testing")
w result.%SQLCODE
The %SQLCODE is set to 0 in this case. The same happens if I use %Prepare and %Execute, e.g.
set statement = ##class(%SQL.Statement).%New()
set status = statement.%Prepare("select top 0 0 from Example.Testing")
set result = statement.%Execute()
w result.%SQLCODE
The documentation suggests that %Execute should in fact set %SQLCODE:
method %Execute(%parm...) as %SQL.StatementResult
Execute the current statement and return the result. The result of the execute is always the return value. Success/Failure information is reported in the result object as %SQLCODE, %Message, %ROWCOUNT, and/or %ROWID.
So does anyone know what's happening here?
I confirm (used the following code):
Quote from the documentation:
Calling @Benjamin De Boe
I can't write you a direct message.
This is expected behaviour. for a SELECT statement, %Execute() (or %ExecDirect()) will set %SQLCODE to 0 if the statement was successfully executed and ready to return rows, or an error code if the execution went wrong. It's through the use of %Next() that it will figure out whether there are any rows left. The first %Next() call on such a resultset will return 0 and at the same time set %SQLCODE to 100. This behaviour is similar and perhaps even more visible in the case of %ROWCOUNT for SELECT statements, which increases with every call to %Next(). See also the docs for %Next() (second bullet)
The simple reason for this is that we're not building the whole result set upfront, but rather "get ready" to iterate through it with %Next() calls, as users may only be interested in the first few rows. Some call this a lazy execution model, but I prefer the term efficient :-). Of course, for DML statements such as UPDATE and DELETE, the %ROWCOUNT is known immediately upon execution, as there is no result set to scan through
Thanks, that makes sense (although it does seem like parts of the documentation are somewhat misleading and could be improved.)
As a follow up question, is there an idiomatic way of checking whether a dynamic SQL SELECT query returns any values then?
That would be through calling %Next() right away. The way how our query code works is to walk through results and tell you when it runs out of rows to pass back.
Our online documentation has a feedback button that makes your comments immediately find their way to the doc writers. They really appreciate suggestions and usually turn them around quite quickly :-)
One of the options:
how can i pass dynamicarray which has args item to this %ExecDirect() method?