Chapter 43 – SQL/CLI: stmt Functions¶
Note
You are reading a digital copy of SQL-99 Complete, Really, a book that documents the SQL-99 standard.
For more information specific to CrateDB, check out the CrateDB Reference.
In this chapter, we’ll describe the third essential CLI resource: the stmt
.
For CLI programs, the stmt
is at the level below dbc
and (usually)
above desc
. The dbc
may contain multiple stmt
s, and the stmt
may contain four desc
s. Here’s a closeup view of a stmt
:
... from dbc
| |
| |
v v
-------------------------------------
- [Attributes] -
- -
- [Diagnostics] -
- -
- [Cursor] [Result Set] [Statement] -
-------------------------------------
| | | |
| | | |
v v v v
... to IPD ... to IRD ... to APD ... to ARD
There are six CLI functions for creating stmt
s, dropping stmt
s,
getting stmt
attributes and setting stmt
attributes. Their
descriptions follow.
Table of Contents
SQLAllocHandle(SQL_HANDLE_STMT,…)¶
Function Prototype:
SQLRETURN SQLAllocHandle (
SQLSMALLINT HandleType, /* 16-bit input = SQL_HANDLE_STMT */
SQLINTEGER InputHandle, /* 32-bit input, must be a hdbc */
SQLINTEGER *OutputHandle /* pointer to 32-bit output, a hstmt */
);
Job: Allocate a stmt
.
Algorithm:
If (HandleType == SQL_HANDLE_STMT) {
If InputHandle is not a valid hdbc:
return error: CLI-specific condition-invalid handle
The dbc's diagnostics area is emptied.
If hdbc is not "connected":
Set *OutputHandle = 0
return error: 08003 connection exception-connection does not exist
If maximum number of stmts has already been made:
Set *OutputHandle = 0
return error: CLI-specific condition-limit on number of handles exceeded
If (dbc's connection is not the current connection)
Change current connection = dbc's connection
If (memory-allocation failure while trying to allocate the new stmt)
Set *OutputHandle = 0
return error: CLI-specific condition-memory allocation error
Make four descs: an IPD, an IRD, an APD, an ARD.
(The four descs have some pre-set values, described in the next chapter.)
Set *OutputHandle = handle of new stmt. }
Notes:
You cannot allocate a
stmt
until you have allocated adbc
and connected (withSQLConnect
).The handle of the new
stmt
is “unique”, which means that there is no otherstmt
in theenv
with the same value. This uniqueness would not be guaranteed if there were twoenv
s, but that’s usually impossible anyway.The Standard calls it the “handle of the allocated SQL-statement”, but in all our examples we name it a
hstmt
, which is the general fashion.Keep the
hstmt
. You’ll need it later forSQLFreeHandle(SQL_HANDLE_STMT...)
and for quite a few other things. In fact, the majority of CLI functions (42 of the 62) take ahstmt
as input.
Example:
#include "sqlcli.h"
...
SQLHDBC hdbc;
SQLHSTMT hstmt;
...
sqlreturn = SQLAllocHandle(SQL_HANDLE_STMT,hdbc,&hstmt);
ODBC: The SQLAllocHandle
function is new in ODBC 3.0.
SQLAllocStmt¶
Function Prototype:
SQLRETURN SQLAllocStmt(
SQLHDBC hdbc, /* 32-bit input, must be a hdbc */
SQLHSTMT *hstmt /* pointer to 32-bit output, a hstmt */
);
Job: Make a new stmt
.
Algorithm:
SQLRETURN = SQLAllocStmt(hdbc,&hstmt);
is the same as
SQLRETURN = SQLAllocHandle(SQL_HANDLE_STMT,hdbc,&hstmt);
Notes:
The Standard does not deprecate
SQLAllocStmt
. All DBMSs should continue to support it. It is, however, redundant.
Example:
#include "sqlcli.h"
...
SQLHDBC hdbc;
SQLHSTMT hstmt;
...
SQLAllocStmt(hdbc,&hstmt);
...
ODBC: The SQLAllocStmt
function has been in ODBC since version 1.0.
The ODBC 3.0 manual deprecates it, suggesting that users should switch to using
SQLAllocHandle(SQL_HANDLE_STMT...)
.
SQLGetStmtAttr¶
Function Prototype:
SQLRETURN SQLGetStmtAttr(
SQLHSTMT hstmt, /* 32-bit input -- statement handle */
SQLINTEGER Attribute, /* 32-bit input */
SQLPOINTER Value, /* pointer to ANY* output */
SQLINTEGER BufferLength, /* 32-bit input */
SQLINTEGER *StringLength); /* pointer to 32-bit output */
Job: Retrieve one attribute of a stmt
.
Algorithm:
If (Attribute == SQL_ATTR_APP_ROW_DESC)
Set *Value = (SQLHDESC) stmt's ARD handle.
If (Attribute == SQL_ATTR_APP_PARAM_DESC)
Set *Value = (SQLHDESC) stmt's APD handle.
If (Attribute == SQL_ATTR_IMP_ROW_DESC)
Set *Value = (SQLHDESC) stmt's IRD handle.
If (Attribute == SQL_ATTR_IMP_PARAM_DESC)
Set *Value = (SQLHDESC) stmt's IPD handle.
If (Attribute == SQL_ATTR_CURSOR_SCROLLABLE)
If (DBMS supports scrollable Cursors)
Set *Value = "Cursor scrollable" attribute (0 or 1) (false or true)
Else
return error: HYC00 CLI-specific condition-optional feature not implemented
If (Attribute == SQL_ATTR_CURSOR_SENSITIVITY)
If (implementation supports sensitive Cursors)
Set *Value = "Cursor sensitivity" attribute (0 or 1 or 2)
Else
return error: HYC00 CLI-specific condition-optional feature not implemented
If (Attribute == SQL_ATTR_METADATA_ID)
Set *Value = "metadata ID" attribute (0 or 1)
If (Attribute == SQL_ATTR_CURSOR_HOLDABLE)
If (implementation supports holdable Cursors)
Set *Value = "Cursor holdable" attribute (0 or 1)
Else
return error: HYC00 CLI-specific condition-optional feature not implemented
If (Attribute == none of the above)
return error: HY092 CLI-specific condition-invalid attribute identifier
Notes:
Here is a list of the standard
stmt
attributes:
VALUE |
|
SETTABLE? |
DATA TYPE |
REMARKS |
---|---|---|---|---|
-3 |
|
yes |
|
ANSI SQL3 only
0=nonholdable
1=holdable
|
-2 |
|
yes |
|
0=asensitive
1=insensitive
2=sensitive
|
-1 |
|
yes |
|
ANSI SQL3 only
0=nonscrollable
1=scrollable
|
10010 |
|
yes |
|
ARD |
10011 |
|
yes |
|
APD |
10012 |
|
no |
|
IRD |
10013 |
|
no |
|
IPD |
10014 |
|
yes |
|
SQL3 only
0=false
1=true
|
Other stmt
attributes may be defined in particular implementations.
(Reminder: SQLHDESC
stands for “handle of a desc
”, a 32-bit value.)
When you allocate a
stmt
(withSQLAllocHandle
orSQLAllocStmt
), the DBMS automatically sets up fourdesc
s: the ARD, the APD, the IRD and the IPD. You can pick up the handles of thesedesc
s by callingSQLGetStmtAttr
withSQL_ATTR_APP_ROW_DESC
,SQL_ATTR_APP_PARAM_DESC
,SQL_ATTR_IMP_ROW_DESC
andSQL_ATTR_IMP_PARAM_DESC
, respectively – you’ll need these because there are several CLI functions which use adesc
handle as input.When you get a result set (by calling
SQLExecDirect
orSQLExecute
for a query expression such as"SELECT ..."
), the DBMS implicitly declares a Cursor. What kind of Cursor? That depends on the “cursor” attributes:SQL_ATTR_CURSOR_SCROLLABLE
if
0
= “false” =SQL_NONSCROLLABLE
: you can only fetchNEXT
.
if1
= “true” =SQL_SCROLLABLE
: you can fetchFIRST
,NEXT
,PRIOR
,LAST
,ABSOLUTE
and RELATIVE``.
The default is0
, but you can callSQLSetStmtAttr
to change that.SQL_ATTR_CURSOR_SENSITIVITY
if
0 = SQL_ASENSITIVE = SQL_UNSPECIFIED
: sensitivity isn’t known.
if1 = SQL_INSENSITIVE
: changes made elsewhere won’t be seen here.
if2 = SQL_SENSITIVE
: changes made elsewhere will be seen here.
The default is0
, but you can callSQLSetStmtAttr
to change that.SQL_ATTR_CURSOR_HOLDABLE
if
0
= “false” =SQL_NONHOLDABLE
: Cursor disappears at transaction end.
if1
= “true” =SQL_HOLDABLE
: Cursor remains at transaction end.
The default is probably 0 (you’d have to callSQLGetInfo
to be certain) but you can callSQLSetStmtAttr
to change that.
When you use a Catalog function (such as
SQLColumns
orSQLTables
), the DBMS has to search the “metadata”, that is, theINFORMATION_SCHEMA
Views. TheSQL_ATTR_METADATA_ID
attribute indicates how searches are conducted with Catalog functions. We discuss this in more detail in our chapter on SQL/CLI Catalog functions.The
BufferLength
andStringLength
parameters aren’t currently in use. They’re there in case we ever have a statement attribute that contains a string value.
Example:
#include "sqlcli.h"
HSTMT hstmt;
HDESC hipd;
...
SQLGetStmtAttr(
hstmt, /* handle of stmt */
SQL_ATTR_IMP_PARAM_DESC, /* we want the IPD handle */
&hipd, /* put the handle here */
NULL, /* "don't care" */
NULL); /* "don't care" */
ODBC: The SQLGetStmtAttr
function is new in ODBC 3.0 (in ODBC 2.0
there was a nearly-equivalent function, SQLGetStmtOption
).
SQLSetStmtAttr¶
Function Prototype:
SQLRETURN SQLSetStmtAttr(
SQLHSTMT hstmt, /* 32-bit input - statement handle */
SQLINTEGER Attribute, /* 32-bit input */
SQLPOINTER Value, /* pointer to ANY* input */
SQLINTEGER StringLength /* 32-bit input */
);
Job: Set an attribute of the stmt
– to change the DBMS’s behaviour
for Cursor control, to change the handle used for an application desc
,
or to change the search method for Catalog functions.
There are eight standard stmt
attributes, listed in the previous section.
Algorithm:
If (Attribute is not one of the settable attributes)
return error: HY092 CLI-specific condition-invalid attribute identifier
If (Attribute == SQL_ATTR_APD_HANDLE)
If (*Value is not the handle of a desc)
return error: HY024 CLI-specific condition-invalid attribute value
If (desc's SQL_ALLOC_TYPE field == 'AUTOMATIC')
If (desc is not stmt's default/automatic APD)
return error: HY017 CLI-specific condition-invalid use of automatically-allocated descriptor handle.
Desc becomes associated with this stmt, as its APD, non-exclusively.
If (Attribute == SQL_ATTR_ARD_HANDLE)
If (*Value is not the handle of a desc)
return error: HY024 CLI-specific condition-invalid attribute value
If (desc's ALLOC_TYPE field == 'AUTOMATIC')
If (desc is not stmt's default/automatic ARD)
return error: HY017 CLI-specific condition-invalid use of automatically-allocated descriptor handle.
Desc becomes associated with this stmt, as its ARD, non-exclusively.
If (Attribute == SQL_ATTR_CURSOR_SCROLLABLE)
If (the DBMS does not support scrollable Cursors)
return error: HYC00 CLI-specific condition-optional feature not implemented
If (stmt already has an open Cursor)
/* You can't change how a Cursor works while the Cursor is open */
return error: HY011 CLI-specific condition-attribute cannot be set now
If (*Value is not SQL_SCROLLABLE (1) or SQL_NONSCROLLABLE (0))
return error: HY011 CLI-specific condition-attribute cannot be set now
Stmt's Cursor's "scrollable" attribute = *Value.
If (Attribute == SQL_ATTR_CURSOR_SENSITIVITY)
If (the DBMS does not support sensitive Cursors)
return error: HYC00 CLI-specific condition-optional feature not implemented
If (there is already an open Cursor for stmt)
return error: HY011 CLI-specific condition-attribute cannot be set now
If (*Value is not SQL_SENSITIVE (2) or SQL_INSENSITIVE (1) or UNSPECIFIED (0))
return error: HY024 CLI-specific condition-invalid attribute value
Stmt's Cursor's "sensitivity" attribute = *Value.
If (Attribute == SQL_ATTR_METADATA_ID)
If (*Value not TRUE or FALSE)
return error: HY024 CLI-specific condition-invalid attribute value
Set stmt's "metadata id" attribute = *Value.
If (Attribute == SQL_ATTR_CURSOR_HOLDABLE)
If (the DBMS does not support holdable Cursors)
return error: HYC00 CLI-specific condition-optional feature not implemented
If (stmt already has an open Cursor)
return error: HY011 CLI-specific condition-attribute cannot be set now
If (*Value is not SQL_HOLDABLE (1) or SQL_NONHOLDABLE (0))
return error: HY024 CLI-specific condition-invalid attribute value
Set stmt's Cursor's "holdable" attribute = Value.
Notes:
The specification allows for implementation-defined attributes and for the possibility of future change. That’s why the
StringLength
parameter exists, although it’s not currently used.SQL_ATTR_APP_ROW_DESC
andSQL_ATTR_APP_PARAM_DESC
are listed as settable attributes, so you can change the stmt’s ARD and APD. (You can’t change thestmt
‘s IRD and IPD.) TheValue
parameter must point to the handle of a userdesc
. This option makes it possible to save or share applicationdesc
s.SQL_ATTR_CURSOR_SCROLLABLE
andSQL_ATTR_CURSOR_HOLDABLE
are used to specify whether astmt
’s Cursor is “scrollable” and/or “holdable”.SQL_ATTR_METADATA_ID
is an abbreviation for “the attribute for metadata identifiers”, for example the names of Tables inINFORMATION_SCHEMA
.It’s easy to forget that the Value parameter is described as
SQLPOINTER
. Don’t make the mistake of passing"hdesc"
(handle of adesc
); pass"&hdesc"
(address of a handle of adesc
) instead.
Example: Change the settings of all settable stmt
attributes. This
example only shows what the syntax looks like for the various options. More
realistic examples will appear in the chapters on “Cursors”, descs
, and
“Catalog functions”.
#include "sqlcli.h"
SQLHSTMT hstmt;
SQLHDESC hdesc1,hdesc2;
SQLINTEGER scrollable = SQL_SCROLLABLE;
SQLINTEGER sensitivity = SQL_INSENSITIVE;
SQLINTEGER metadata_id = SQL_FALSE;
SQLINTEGER holdable = SQL_NONHOLDABLE;
...
SQLSetStmtAttr(hstmt,SQL_ATTR_APP_ROW_DESC,&hdesc1,NULL);
SQLSetStmtAttr(hstmt,SQL_ATTR_APP_PARAM_DESC,&hdesc2,NULL);
SQLSetStmtAttr(hstmt,SQL_ATTR_CURSOR_SCROLLABLE,&scrollable,NULL);
SQLSetStmtAttr(hstmt,SQL_ATTR_CURSOR_SENSITIVITY,&sensitivity,NULL);
SQLSetStmtAttr(hstmt,SQL_ATTR_METADATA_ID,&metadata_id,NULL);
SQLSetStmtAttr(hstmt,SQL_ATTR_CURSOR_HOLDABLE,&holdable,NULL);
ODBC: The SQLSetStmtAttr
function is new in ODBC 3.0 but there was
a similar function in ODBC 2.0 (SQLSetStmtOption
).
SQLFreeHandle(SQL_HANDLE_STMT,…)¶
Function Prototype:
SQLRETURN SQLFreeHandle( /* function returns SMALLINT */
SQLSMALLINT HandleType, /* 16-bit input, = SQL_HANDLE_STMT */
SQLINTEGER Handle /* 32-bit input, must be a hstmt */
);
Job: Destroy a stmt
.
Algorithm:
If (HandleType == SQL_HANDLE_STMT)
If (Handle is not a hstmt)
return error: CLI-specific condition-invalid handle
Empty the stmt's diagnostics area.
The stmt's dbc becomes the "current dbc".
If (there is a deferred parameter associated with stmt)
return error: HY010 CLI-specific condition-function sequence error
If (there is an open Cursor associated with the stmt)
Throw away all information about the Cursor's result set
Close the Cursor
Deallocate the stmt's four automatic descs: ARD, APD, IRD, IPD.
Deallocate stmt.
Notes:
Correctly speaking, this functions “frees the
stmt
”; it doesn’t merely free thestmt
’s handle.The DBMS calls
SQLFreeHandle(SQL_HANDLE_STMT...)
implicitly, for allstmt
s in adbc
, as part of anSQLDisconnect
operation.There is a mention here of a “current”
dbc
. If there are multipledbc
s, the DBMS will implicitly switch, when necessary, to thedbc
whose handle is passed in the function call (or, as in this case, to thedbc
associated with thestmt
whose handle is passed in the function call). This switching is transparent. There is no need, when using the CLI, for any analogue of the basic SQL"SET CONNECTION ..."
statement.Freeing a statement causes an implicit “close Cursor” operation, but not an implicit “end transaction” operation.
Quite often, programmers allocate a
stmt
only once, and re-use the samestmt
throughout the SQL-session. SoSQLFreeHandle(SQL_HANDLE_STMT...)
may be seen only infrequently.
Example:
#include "sqlcli.h"
SQLHDBC hdbc;
SQLHSTMT hstmt;
...
SQLAllocHandle(SQL_HANDLE_STMT,hdbc,&hstmt);
...
SQLFreeHandle(SQL_HANDLE_STMT,hstmt);
ODBC: The SQLFreeHandle
function is new in ODBC 3.0.
SQLFreeStmt¶
Function Prototype:
SQLRETURN SQLFreeStmt(
SQLHSTMT hstmt, /* 32-bit input */
SQLSMALLINT Option; /* 16-bit input */
);
Job:
SQLFreeStmt
has five different jobs, depending on the value of
Option
:
If
Option
is 0,SQLFreeStmt
’s job is to close a Cursor.If
Option
is 1,SQLFreeStmt
’s job is to destroy astmt
.If
Option
is 2,SQLFreeStmt
’s job is to unbind Columns.If
Option
is 3,SQLFreeStmt
’s job is to unbind parameters.If
Option
is 4,SQLFreeStmt
’s job is to reallocate.
Algorithm:
If (Option == SQL_CLOSE (0))
If (there is a Cursor)
Cancel all information about the result set.
Close the Cursor.
If (Option == SQL_DROP (1))
/* SQLFreeStmt(...,SQL_DROP) is the reverse of SQLAllocStmt(...).
sqlreturn = SQLFreeStmt(hstmt,SQL_DROP);
is the same as:
sqlreturn = SQLFreeHandle(SQL_HANDLE_STMT,hstmt);
If (Option == SQL_UNBIND (2))
/* This affects the application row descriptor (ARD). In
effect, it cancels out any SQLBindCol calls made on stmt. */
For (i=1; i<=ARD.SQL_DESC_COUNT;++i)
Set ARD.IDA[i].SQL_DESC_DATA_POINTER = 0
If (Option == SQL_RESET_PARAMS (3))
/* This affects the application parameter descriptor (APD). In
effect, it cancels out any SQLBindParameter calls made on stmt. */
For (i=1; i<=APD.SQL_DESC_COUNT;++i)
Set APD.IDA[i].SQL_DESC_DATA_POINTER = 0
If (Option == SQL_REALLOCATE (4))
Destroy the stmt's statement and Cursor parts
If (Option == none of the above)
return error: HY092 CLI-specific condition-invalid attribute identifier
Notes:
Regrettably, we are forced to mention a few details before their time for full discussion is come. For the immediate purpose, we hope it is enough to say that:
RESULT SETS
are temporary Tables which result from the execution of an SQL query.Cursors
are named interface objects through which result sets can be retrieved one row at a time.BINDINGS
are associations between a host program’s host variables (i.e.: pointers to data buffers and indicator variables) and their corresponding SQL Objects (Columns and/or parameter markers). Often Columns are bound with theSQLBindCol
function, while parameters are bound with theSQLBindParameter
function.
Because
SQLFreeHandle
is now the main function for freeing resources, the nameSQLFreeStmt
is now a misnomer – we don’t useSqlFreeStmt
for freeingstmt
s nowadays. However, it maintains a residue of usefulness. It’s good for “partialstmt
freeing”, freeing things associated withstmt
s that might be taking up space, or whose continued existence might cause conflict with other operations.SQLFreeStmt(...,SQL_CLOSE)
does exactly the same thing as theSQLCloseCursor
function, except for one detail: if there is no Cursor currently open, thenSQLCloseCursor
returns an error, whileSQLFreeStmt(...,SQL_CLOSE)
does not return an error.SQLFreeStmt(hstmt,SQL_DROP)
is now just another way of saying:SQLFreeHandle(SQL_HANDLE_STMT,hstmt)
.SQLFreeStmt(...,SQL_UNBIND)
andSQLFreeStmt(...,SQL_RESET_PARAMS)
are handy ways of “disassociating” the application’s RAM from the DBMS, so that there won’t be inadvertent access to memory that’s no longer valid. Here’s an example:x=malloc(1024); /* malloc an area */ SQLBindCol(...,x,...); /* Now there is a binding to the malloc'd area */ free(x); /* uh oh. x is no longer a valid pointer */ SQLFreeStmt(...,UNBIND ColumnS); /* okay, chances of GPF are reduced */
However, only the “data pointer” field is cleared – not the “indicator pointer” field (this is probably an inadvertent omission from the Standard).
SQLFreeStmt(...,SQL_REALLOCATE)
can be used to clear parts ofstmt
s:The “statement” (a copy of the SQL statement string which was last prepared or executed for this
stmt
, including “select” source statements).The “Cursor”, including the Cursor’s result set. These things take up space, so presumably
SQLFreeStmt(...,SQL_REALLOCATE)
is useful under low-memory conditions. But normally it’s unnecessary: “statement” and “Cursor” are superseded in any case when an SQL statement is re-prepared/re-executed.
Example: Since SQLFreeStmt(...,SQL_DROP)
is the reverse of
SQLAllocStmt(...)
, we show both these obsolescent calls together.
#include "sqlcli.h"
SQLHDBC hdbc;
SQLHSTMT hstmt;
...
SQLAllocStmt(hdbc,&hstmt); /* allocate a stmt */
SQLBindCol(hstmt,...); /* bind a stmt Column */
SQLFreeStmt(hstmt,SQL_UNBIND); /* unbind all stmt Columns */ ...
SQLFreeStmt(hstmt,SQL_DROP); /* free a stmt */
ODBC: The SQLFreeStmt
function has been in ODBC since version 1.0. The
ODBC 3.0 manual deprecates the use of SQLFreeStmt(...,SQL_DROP)
, suggesting
that the user should switch to using SQLFreeHandle(SQL_HANDLE_STMT,...)
.
The ODBC action for SQL_UNBIND
is different: ARD.SQL_DESC_COUNT
is set
to 0. The ODBC action for SQL_RESET_PARAMS
is different:
APD.SQL_DESC_COUNT
is set to 0. The SQL_REALLOCATE
option is not
supported.
And that’s it for the stmt
functions. In the next chapter, we’ll take a
look at the statement functions.