Chapter 47 – SQL/CLI: Diagnostic 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.
What if something goes wrong? Every env
and dbc
and stmt
and
desc
has a structure called the Diagnostics Area. The DBMS fills it with
information about what happened during the last function call. The diagnostics
area has one “header” and zero or more “status records”. This partial
illustration shows only the most important fields:
-----------------------------------------
- SQL_DIAG_RETURNCODE | SQL_DIAG_NUMBER -
- --------------------+------------------
- - -1 | 00003 |
-----------------------------------------
-
- ----------------------------------------------------------------------
- - SQL_DIAG_SQLSTATE | SQL_DIAG_MESSAGE_TEXT | ... |
- ---------------------------------------------------------------------
- 1 - 23000 | Integrity Constraint Violation - constraint <X> | ... |
- 2 - 01003 | Warning - null value eliminated in set function | ... |
- 3 - 01008 | Warning - implicit zero-bit padding | ... |
- ---------------------------------------------------------------------
This diagram shows the diagnostics area of a stmt
, just after this function
call:
sqlreturn = SQLExecDirect(
hstmt,"UPDATE T SET a=(SELECT MAX(b) FROM X),c=X'5'",SQL_NTS);
Looking at the header, we can see that the function failed because the
SQL_DIAG_RETURNCODE
field is -1, which is SQL_ERROR
(sqlreturn
will
also equal -1). Also, from the fact that the header’s SQL_DIAG_NUMBER
field
is 3, we can see that there are three status records.
Looking at the status records, we can see that three different things went
wrong during the execution of the SQL statement. Two of them were merely
warnings (“completion conditions”). Probably the DBMS encountered these
conditions while it was setting up for the UPDATE
, but it kept on going.
Then it hit a showstopper: an “exception condition”. Although this “integrity
Constraint violation” error was the third condition encountered, it is the
first in order among the status records because an error’s priority is higher
than a warning’s.
The SQL_DIAG_SQLSTATE
field contains a code for a reasonably precise
categorization of the condition. This code is called the status code, or
SQLSTATE
value (because the DBMS always puts the status code in the
SQL_DIAG_SQLSTATE
field). You can see what the SQLSTATE
codes mean by
looking at the chart of codes at the end of this chapter.
The SQL_DIAG_MESSAGE_TEXT
field might be the sort of text you’d like to
send to the user’s screen for this condition. Unlike the status code, the
message text is implementation-dependent: it’s not standardized. It might be
internationalized; that is, it might not be in English. So there is a lot more
information here than a mere “failed” return code. And there are many more
fields than the ones in the picture, which can help you get an even more
precise diagnosis of “why didn’t the SQLExecDirect
function work”. In order
to retrieve the diagnostics-area information into your application program, you
need to use one of these CLI functions:
SQLGetDiagField
– You’ll need this function to get any field from any part of the diagnostics area, one field at a time.SQLGetDiagRec
– With this function, you can pick up several of the most popular fields, includingSQL_DIAG_SQLSTATE
andSQL_DIAG_MESSAGE_TEXT
.SQLError
– You’ll want to know about this slightly obsolescent function because it appears frequently in legacy code.SQLRowCount – This isn’t exactly a diagnostics function, but it does get a value from a particular diagnostics-area field:
SQL_DIAG_ROW_COUNT
.
The descriptions of these four functions follow.
Table of Contents
SQLGetDiagField¶
Function Prototype:
SQLRETURN SQLGetDiagField(
SQLSMALLINT HandleType, /* 16-bit input */
SQLINTEGER Handle, /* 32-bit input */
SQLSMALLINT RecordNumber, /* 16-bit input */
SQLSMALLINT DiagIdentifier, /* 16-bit input */
SQLPOINTER DiagInfo, /* ANY* output */
SQLSMALLINT BufferLength, /* 16-bit input */
SQLSMALLINT *StringLength /* 16-bit output */
);
Job: Get one piece of information from a diagnostics area, for example, the
SQLSTATE
of a warning that was posted for the last function call.
There are 50 variations of SQLGetDiagField
, depending on the diagnostics
field whose value you want to examine. Here’s an example and short description
of each variation; each uses these shorthands:
The words “last call” mean “the last function called using this handle, other than
SQLGetDiagField
orSQLGetDiagRec
orSQLError
”. The principle (anti-Heisenbergian) here is that the act of observation must not affect the thing observed, so the diagnostics routines don’t themselves post diagnostics information.The punctuation …,…, at the beginning of each function example’s parameter list means “assume there is a valid handle type and handle here”. The
HandleType
parameter must beSQL_HANDLE_ENV
,SQL_HANDLE_DBC
,SQL_HANDLE_STMT
orSQL_HANDLE_DESC
. The corresponding Handle parameter must be ahenv
orhdbc
orhstmt
orhdesc
. Where the only acceptable value is ahstmt
, the parameter list starts withSQL_HANDLE_STMT,hstmt
.The name used for the
DiagInfo
parameter gives an indication of the <data type> thatSQLGetDiagField
returns: smallint, integer or character string.The word
NULL
in a function’s argument list means “doesn’t matter”. None of the diagnostics fields containNULL
in the SQL sense.The four-digit number at the beginning of each paragraph is the code for the
DiagIdentifier
parameter. We have done the same thing here that we did in our chapter on thedesc
functions; namely, treating the name of thesqlcli.h
code constant as the name of the field.
Diagnostics Fields – Header¶
The nine “Header” fields in a diagnostics area occur only once. It does not
matter what you pass for the RecordNumber
parameter.
0001
SQLGetDiagField(...,...,NULL,SQL_DIAG_RETURNCODE,&smallint,NULL,NULL);
This field gives you the last call’s return code:
SQL_SUCCESS
,SQL_ERROR
,SQL_SUCCESS_WITH_INFO
,SQL_NEED_DATA
orSQL_NO_DATA
. You need to call this if you failed to save the return code in ansqlreturn
variable.0002
SQLGetDiagField(...,...,NULL,SQL_DIAG_NUMBER,&integer,NULL,NULL);
This field gives you the number of Status Records (exception or completion conditions) that the DBMS generated for the last call. The value will be zero if the return code is
SQL_SUCCESS
, and will probably (but not certainly) be zero if the return code isSQL_NO_DATA
.0003
SQLGetDiagField( SQL_HANDLE_STMT,hstmt,NULL,SQL_DIAG_ROW_COUNT,&integer,NULL,NULL);
If the last call was
SQLExecDirect
orSQLExecute
for anUPDATE
,DELETE
orINSERT
statement, this field gives you the number of rows affected. Read about theSQLRowCount
function, which returns the same information. You must call this function immediately after callingSQLExecDirect
orSQLExecute
.0007
SQLGetDiagField( SQL_HANDLE_STMT,hstmt,NULL,SQL_DIAG_DYNAMIC_FUNCTION,charstring, sizeof(charstring),&charstring_size);
If the last call was
SQLExecDirect
orSQLExecute
, this field gives you a string that describes the type of SQL statement executed. Usually this is the first two or three <keyword>s in the statement. The official list of SQL statements and their function codes is shown at the end of this section.0012
SQLGetDiagField( SQL_HANDLE_STMT,hstmt,NULL,SQL_DIAG_DYNAMIC_FUNCTION_CODE, &integer,NULL,NULL);
If the last call was
SQLExecDirect
orSQLExecute
, this field gives you the code value for the type of SQL statement executed; see the codes in the “DYNAMIC_FUNCTION
andDYNAMIC_FUNCTION_CODE
” lists, above. If you allow users to type in SQL statements, it’s handy to callSQLPrepare
and then call this function, so you know what kind of SQL statement it is before you callSQLExecute
.0013
SQLGetDiagField(SQL_HANDLE_STMT,hstmt,NULL,SQL_DIAG_MORE,&integer,NULL,NULL);
The return value for this field is either 1 “true” or 0 “false”: if there are more status records than would fit in the diagnostics area, you get a “true” code here. (Actually the Standard says that the returned value is ‘Y’ or ‘N’ but that must be an error.) You may or may not be able to change the maximum size of the diagnostics area with
SET TRANSACTION ... DIAGNOSTICS SIZE
statement.0034
SQLGetDiagField( ...,...,NULL,SQL_DIAG_TRANSACTIONS_COMMITTED,&integer,NULL,NULL);
This field gives you the number of transactions committed.
0035
SQLGetDiagField( ...,...,NULL,SQL_DIAG_TRANSACTIONS_ROLLED_BACK,&integer,NULL,NULL);
This field gives you the number of transactions rolled back.
0036
SQLGetDiagField(...,...,NULL,SQL_DIAG_TRANSACTION_ACTIVE,&integer,NULL,NULL);
This field gives you a 1 “true” if a transaction is currently active. (A transaction is active if a Cursor is open or the DBMS is waiting for a deferred parameter.)
SQL_DIAG_DYNAMIC_FUNCTION Codes¶
If the last call was SQLExecDirect
or SQLExecute
,
SQLGetDiagField
's SQL_DIAG_DYNAMIC_FUNCTION
gives you a string that
describes the type of SQL statement executed. As we said earlier, this is
usually the first two or three <keyword>s in the SQL statement. Here’s the
official list of SQL statements and their function codes (note that not all
these SQL statements are executable in a CLI context; we have given a full list
here so as to avoid repetition elsewhere).
List of SQL Statements and Codes in SQL-92, but not in CLI¶
DYNAMIC_FUNCTION DYNAMIC_FUNCTION_CODE
(string) (number) (sqlcli.h definition)
ALLOCATE CURSOR 1 not defined
ALLOCATE DESCRIPTOR 2 not defined
CREATE TRANSLATION 79 not defined
DEALLOCATE DESCRIPTOR 15 not defined
DEALLOCATE PREPARE 16 not defined
DESCRIBE 20 not defined
DYNAMIC CLOSE 37 not defined
DYNAMIC DELETE CURSOR: 38 not defined
(positioned)
DYNAMIC FETCH 39 not defined
DYNAMIC OPEN 40 not defined
DYNAMIC UPDATE CURSOR: 42 not defined
(positioned)
EXECUTE 44 not defined
EXECUTE IMMEDIATE 43 not defined
FETCH 45 not defined
GET DESCRIPTOR 47 not defined
PREPARE 56 not defined
SELECT (multiple row) 21 not defined
SET CURRENT_PATH 69 not defined
SET DESCRIPTOR 70 not defined
List of Additional SQL Statements and Codes in SQL-92 and CLI¶
DYNAMIC_FUNCTION DYNAMIC_FUNCTION_CODE
(string) (number) (sqlcli.h definition)
'' 0 <unknown statement type>
ALTER DOMAIN 3 SQL_DIAG_ALTER_DOMAIN
ALTER TABLE 4 SQL_DIAG_ALTER_TABLE
CLOSE CURSOR 9 SQL_DIAG_CLOSE_CURSOR
COMMIT WORK 11 SQL_DIAG_COMMIT
CONNECT 13 SQL_DIAG_CONNECT
CREATE ASSERTION 6 SQL_DIAG_CREATE_ASSERTION
CREATE CHARACTER SET 8 SQL_DIAG_CREATE_CHARACTER_SET
CREATE COLLATION 10 SQL_DIAG_CREATE_COLLATION
CREATE DOMAIN 23 SQL_DIAG_CREATE_DOMAIN
CREATE SCHEMA 64 SQL_DIAG_CREATE_SCHEMA
CREATE TABLE 77 SQL_DIAG_CREATE_TABLE
CREATE VIEW 84 SQL_DIAG_CREATE_VIEW
DECLARE CURSOR 101 SQL_DIAG_DECLARE_CURSOR
DELETE CURSOR 18 SQL_DIAG_DELETE_CURSOR
DELETE WHERE 19 SQL_DIAG_DELETE_WHERE
DISCONNECT 22 SQL_DIAG_DISCONNECT
DROP ASSERTION 24 SQL_DIAG_DROP_ASSERTION
DROP CHARACTER SET 25 SQL_DIAG_DROP_CHARACTER_SET
DROP COLLATION 26 SQL_DIAG_DROP_COLLATION
DROP DOMAIN 27 SQL_DIAG_DROP_DOMAIN
DROP SCHEMA 31 SQL_DIAG_DROP_SCHEMA
DROP TABLE 32 SQL_DIAG_DROP_TABLE
DROP TRANSLATION 33 SQL_DIAG_DROP_TRANSLATION
DROP VIEW 36 SQL_DIAG_DROP_VIEW
DYNAMIC DELETE CURSOR: 54 SQL_DIAG_DYNAMIC_DELETE_CURSOR
(preparable, positioned)
DYNAMIC UPDATE CURSOR 55 SQL_DIAG_DYNAMIC_UPDATE_CURSOR
(preparable, positioned)
GRANT 48 SQL_DIAG_GRANT
INSERT 50 SQL_DIAG_INSERT
OPEN 53 SQL_DIAG_OPEN
REVOKE 59 SQL_DIAG_REVOKE
ROLLBACK WORK 62 SQL_DIAG_ROLLBACK
SELECT (single row) 65 SQL_DIAG_SELECT
SELECT (dynamic single row) 41 SQL_DIAG_SELECT
SELECT CURSOR 85 SQL_DIAG_SELECT_CURSOR
(dynamic multiple row)
SET CATALOG 66 SQL_DIAG_SET_CATALOG
SET CONNECTION 67 SQL_DIAG_SET_CONNECTION
SET CONSTRAINT 68 SQL_DIAG_SET_CONSTRAINT
SET NAMES 72 SQL_DIAG_SET_NAMES
SET TIME ZONE 71 SQL_DIAG_SET_TIME_ZONE
SET SESSION AUTHORIZATION 76 SQL_DIAG_SET_SESSION_AUTHORIZATION
SET SCHEMA 74 SQL_DIAG_SET_SCHEMA
SET TRANSACTION 75 SQL_DIAG_SET_TRANSACTION
UPDATE CURSOR (positioned) 81 SQL_DIAG_UPDATE_CURSOR
UPDATE WHERE 82 SQL_DIAG_UPDATE_WHERE
List of Additional SQL Statements and Codes in SQL3, but not in CLI¶
DYNAMIC_FUNCTION DYNAMIC_FUNCTION_CODE
(string) (number) (sqlcli.h definition)
ALTER MODULE 95 not defined
ALTER ROUTINE 17 not defined
ALTER TYPE 60 not defined
ASSIGNMENT 5 not defined
BEGIN END 12 not defined
CASE 86 not defined
CREATE MODULE 51 not defined
CREATE ORDERING 114 not defined
CREATE TRANSFORM 117 not defined
DECLARE VARIABLE 96 not defined
DROP MODULE 28 not defined
FOR 46 not defined
FREE LOCATOR 98 not defined
HANDLER 87 not defined
HOLD LOCATOR 99 not defined
IF 88 not defined
LEAVE 89 not defined
LOOP 90 not defined
RESIGNAL 91 not defined
SET TRANSFORM GROUP 118 not defined
SIGNAL 92 not defined
TEMPORARY TABLE 93 not defined
WHILE 97 not defined
List of Additional SQL Statements and Codes in SQL3 and CLI¶
DYNAMIC_FUNCTION DYNAMIC_FUNCTION_CODE
(string) (number) (sqlcli.h definition)
CALL 7 SQL_DIAG_CALL
CREATE ROLE 61 SQL_DIAG_CREATE_ROLE
CREATE ROUTINE 14 SQL_DIAG_CREATE_ROUTINE
CREATE TRIGGER 80 SQL_DIAG_CREATE_TRIGGER
CREATE TYPE 83 SQL_DIAG_CREATE_TYPE
DROP ROLE 29 SQL_DIAG_DROP_ROLE
DROP ROUTINE 30 SQL_DIAG_DROP_ROUTINE
DROP TRANSFORM 116 SQL_DIAG_DROP_TRANSFORM
DROP TRIGGER 34 SQL_DIAG_DROP_TRIGGER
DROP ORDERING 115 SQL_DIAG_DROP_ORDERING
DROP TYPE 35 SQL_DIAG_DROP_TYPE
GRANT ROLE 49 SQL_DIAG_GRANT_ROLE
RELEASE SAVEPOINT 57 SQL_DIAG_RELEASE_SAVEPOINT
RETURN 58 SQL_DIAG_RETURN
REVOKE ROLE 60 SQL_DIAG_REVOKE_ROLE
SAVEPOINT 63 SQL_DIAG_SAVEPOINT
SET ROLE 73 SQL_DIAG_SET_ROLE
SET SESSION CHARACTERISTICS 109 SQL_DIAG_SET_SESSION_CHARACTERISTICS
START TRANSACTION 111 SQL_DIAG_START_TRANSACTION
(Note: In some contexts, the names DYNAMIC_FUNCTION
and
DYNAMIC_FUNCTION_CODE
are COMMAND_FUNCTION
and
COMMAND_FUNCTION_CODE
, respectively.)
Diagnostics Fields – Status Records¶
The 28 “status records” in a diagnostics area can occur multiple times. You
must pass a record number between 1 and SQL_DIAG_NUMBER
(or you can pass
any positive number and see whether SQLGetDiagField
returns
SQL_NO_DATA
). Other terms for Status Record are: “Descriptor Record”
(preferred by Microsoft) and Condition Information Item (preferred by the SQL
Standard in non-CLI contexts). Strings are returned according to the rules of
Character String Retrieval.
< 0
A status record with a number less than zero identifies an implementation-defined diagnostics field.
0004
SQLGetDiagField( ...,...,n,SQL_DIAG_SQLSTATE,charstring,sizeof(charstring), &charstring_size);
This field gives you a 5-character status code – remember to allow 6 characters because of the null terminator.
SQLSTATE
is the most important diagnostics field. You’ll find the complete list ofSQLSTATE
values, often called simply status codes, at the end of this chapter. Quite often, theSQLSTATE
class determines whether the other diagnostics fields have meaningful values.0005
SQLGetDiagField(...,...,n,SQL_DIAG_NATIVE,&integer,NULL,NULL);
This field gives you an integer which has an implementation-defined numeric code for the error type. If your DBMS has been around for a few years, this will be the same as the
SQLCODE
value. It was once standard for DBMSs to returnSQLCODE
, and sometimes (for instance with IBM’s DB2) theSQLCODE
is more informative than theSQLSTATE
value. But there is no standardized interpretation for the codes, except that values less than zero are “errors”, equal to zero is “success”, greater than zero are “warnings”, and specifically +100 is “warning-no data”.0006
SQLGetDiagField( ...,...,n,SQL_DIAG_MESSAGE_TEXT,charstring,sizeof(charstring), &charstring_size);
This field gives you an error message – sometimes merely an explanation of the
SQLSTATE
meaning, but the better DBMSs have context-sensitive tips. Useful for displays. Often, due to an ODBC requirement, messages start with bracketed information about the server and driver.0008
SQLGetDiagField( ...,...,n,SQL_DIAG_CLASS_ORIGIN,charstring,sizeof(charstring), &charstring_size);
This field gives you the naming authority responsible for the definition of the class (the first two letters of
SQLSTATE
). Example: ‘ISO 9075’ would mean that the condition is documented in ISO/IEC 9075:1992 and is therefore “standard”.0009
SQLGetDiagField( ...,...,n,SQL_DIAG_SUBCLASS_ORIGIN,charstring,sizeof(charstring), &charstring_size);
This field gives you the naming authority responsible for the definition of the subclass (the last three letters of
SQLSTATE
). Example: ‘ODBC 3.0’ would mean that the condition is documented in Microsoft’s ODBC manual version 3.0 but is not in any ISO specification, and is therefore “not standard”.0010
SQLGetDiagField( ...,...,n,SQL_DIAG_CONNECTION_NAME,charstring,sizeof(charstring), &charstring_size);
This field gives you the <Connection name>. With the CLI this field is of minor importance, because the primary identifier for an SQL-Connection is the
hdbc
.0011
SQLGetDiagField( ...,...,n,SQL_DIAG_SERVER_NAME,charstring,sizeof(charstring), &charstring_size);
If the last SQL statement was a failed
CONNECT
,DISCONNECT
orSET CONNECTION
, this field gives you the server that the attempt failed with. Otherwise, you get the same information that you’d get by callingSQLGetInfo(...,SQL_DATA_SOURCE_NAME,...)
.0014
SQLGetDiagField(...,...,n,SQL_DIAG_CONDITION_NUMBER,&integer,NULL,NULL);
This field gives you the number of the Status Record (the terms “condition number” and “status record number” are synonymous). This will be the same thing as the
RecordNumber
parameter, so you won’t find out anything new here.0015
SQLGetDiagField( ...,...,n,SQL_DIAG_CONSTRAINT_CATALOG,charstring,sizeof(charstring), &charstring_size);
0016
SQLGetDiagField( ...,...,n,SQL_DIAG_CONSTRAINT_SCHEMA,charstring,sizeof(charstring), &charstring_size);
0017
SQLGetDiagField( ...,...,n,SQL_DIAG_CONSTRAINT_NAME,charstring,sizeof(charstring), &charstring_size);
If
SQLSTATE
is'23000'
(integrity constraint violation) or'27000'
(triggered data change violation) or'40002'
(transaction rollback-integrity constraint violation), then fields0015
,0016
and0017
give you the Catalog, Schema and name of the violated Constraint.0018
SQLGetDiagField( ...,...,n,SQL_DIAG_CATALOG_NAME,charstring,sizeof(charstring), &charstring_size);
0019
SQLGetDiagField( ...,...,n,SQL_DIAG_SCHEMA_NAME,charstring,sizeof(charstring), &charstring_size);
0020
SQLGetDiagField( ...,...,n,SQL_DIAG_TABLE_NAME,charstring,sizeof(charstring), &charstring_size);
0021
SQLGetDiagField( ...,...,n,SQL_DIAG_COLUMN_NAME,charstring,sizeof(charstring), &charstring_size);
Fields
0018
,0019
,0020
and0021
give you the Catalog, Schema and Table identifiers, plus the Column identifier if applicable, for what “caused” the problem. IfSQLSTATE = '23000'
or'27000'
or'40002'
, these fields will identify the Table that the violated Constraint is associated with (assuming there is one such Table). IfSQLSTATE = '42000'
, this is the Object that couldn’t be found or that you lack Privileges on (the Standard contains some ambiguities here, but it seems that these fields may be blank for access violations). IfSQLSTATE = '44000'
, this is the View that has a violatedWITH CHECK OPTION
. IfSQLSTATE = '09000'
or'40004'
, this is the Table with the Trigger that can’t be executed. IfSQLSTATE
is any other value, results are implementation-dependent.0022
SQLGetDiagField( ...,...,n,SQL_DIAG_CURSOR_NAME,charstring,sizeof(charstring), &charstring_size);
If
SQLSTATE = '01001'
or'24000'
, this field gives you the identifier of a Cursor. IfSQLSTATE
is anything else, results are implementation-dependent.0023
SQLGetDiagField(...,...,n,SQL_DIAG_MESSAGE_LENGTH,&integer,NULL,NULL);
This field gives you the character length of the implementation-defined message string. You can get the same information using
SQL_DIAG_MESSAGE_TEXT
. By the way, the C include filesqlcli.h
says “#define SQL_MAXIMUM_MESSAGE_LENGTH 512
” so the suggestion is that you allow 512 bytes for the message – but it’s only a suggestion. It might be interesting to compareSQL_MAXIMUM_MESSAGE_LENGTH
with whatSQLGetDiagField
returns forSQL_DIAG_MESSAGE_LENGTH
.0024
SQLGetDiagField(...,...,n,SQL_DIAG_MESSAGE_OCTET_LENGTH,&integer,NULL,NULL);
This field gives you the octet length of the implementation-defined message string. This will be the same as the message length in characters if the Character set is 8-bit.
0025
SQLGetDiagField( ...,...,n,SQL_DIAG_CONDITION_NAME,&charstring,sizeof(charstring), &charstring_size);
This field gives you the name of an unhandled user-defined exception.
0026
SQLGetDiagField( ...,...,n,SQL_DIAG_PARAMETER_NAME,charstring,sizeof(charstring), &charstring_size);
This field gives you the name of a parameter – presumably the parameter which contained bad (input) data. Since named parameters are not a universal feature, most DBMSs will not return anything here.
0027
SQLGetDiagField( ...,...,n,SQL_DIAG_ROUTINE_CATALOG,charstring,sizeof(charstring), &charstring_size);
0028
SQLGetDiagField( ...,...,n,SQL_DIAG_ROUTINE_SCHEMA,charstring,sizeof(charstring), &charstring_size);
0029
SQLGetDiagField( ...,...,n,SQL_DIAG_ROUTINE_NAME,charstring,sizeof(charstring), &charstring_size);
0030
SQLGetDiagField( ...,...,n,SQL_DIAG_SPECIFIC_NAME,charstring,sizeof(charstring), &charstring_size);
If the
SQLSTATE
error class is ‘38’ (external routine exception) or ‘39’ (external routine invocation exception), fields0027
,0028
and0029
give you the full identifier of the routine that “caused” the error, while field0030
gives you the routine’s specific name.0031
SQLGetDiagField( ...,...,n,SQL_DIAG_TRIGGER_CATALOG,charstring,sizeof(charstring), &charstring_size);
0032
SQLGetDiagField( ...,...,n,SQL_DIAG_TRIGGER_SCHEMA,charstring,sizeof(charstring), &charstring_size);
0033
SQLGetDiagField( ...,...,n,SQL_DIAG_TRIGGER_NAME,charstring,sizeof(charstring), &charstring_size);
If
SQLSTATE='40004'
or'09000'
, fields0031
,0032
and0033
give you the full identifier of the Trigger that “caused” the problem.
Algorithm:
If (HandleType <> SQL_HANDLE_STMT, SQL_HANDLE_ENV, SQL_HANDLE_DBC, or
SQL_HANDLE)DESC)
return error: CLI-specific condition-invalid handle
If (handle isn't really the type indicated by HandleType)
return error: CLI-specific condition-invalid handle
If (DiagIdentifier isn't a valid code)
return error: HY024 CLI-specific condition-invalid attribute value
If (FieldIdentifier is for one of the Status Record fields)
If (RecordNumber < 1)
return error: 35000 invalid condition number -
If (RecordNumber > actual number of status records)
return warning: 01000 no data -
If (FieldIdentifier is for one of the Header fields)
If (FieldIdentifier == SQL_DIAG_ROW_COUNT)
If (last call was not SQLExecute or SQLExecDirect)
return error: HY092 CLI-specific condition-invalid attribute identifier
Otherwise: return a diagnostics-area field, as already described.
Notes:
Status Records are sorted according to the severity of the error class:
Highest: Errors that cause rollback (class ‘40’).
Lower: Ordinary errors (everything except ‘40’ or ‘01’ or ‘02’).
Lower: No-data warning (class ‘02’).
Lowest: Mere warning (class ‘01’).
The first Status Record is thus the most important. If the return code is
SQL_ERROR
you can be sure that the first Status Record describes an error condition.The
SQLSTATE
s associated with the possibleSQLGetDiagField
errors are only mentioned for documentary reasons. TheSQLGetDiagField
function does not itself post any diagnostics. The way you check for errors is: look at the return code, then start guessing. These tips may be useful:If (SQLGetDiagField returns SQL_SUCCESS_WITH_INFO) Probably the DiagInfo buffer is too small. Compare BufferLength (the maximum size of the DiagInfo buffer) to StringLength (the actual size of the string to be returned). If BufferLength is smaller, there's your problem. If (SQLGetDiagField returns SQL_INVALID_HANDLE) Sure, check that the handle is valid. But this problem can also occur if SQLHandleType is not SQL_HANDLE_..., so check that too. If (SQLGetDiagField returns SQL_ERROR) Check HandleType+DiagIdentifier. If the handle isn't a hstmt, then you can't ask for SQL_ROW_COUNT. Check RecordNumber. If you're looking for a header field, then it doesn't matter what you pass in RecordNumber. If you're looking for a status field, then RecordNumber must be >= 1. Check DiagIdentifier. If you use constants defined in sqlcli.h: the value here should be a constant beginning with SQL_DIAG_... -- but that's not enough. Also, make sure it's one of the values listed above. Check BufferLength. If you're looking for a numeric field, then it doesn't matter what you pass in BufferLength. If you're looking for a string field, then BufferLength must be >= 1. If (SQLGetDiagField returns SQL_NO_DATA) This always means that the value you passed in RecordNumber is greater than the value in the diagnostics area's NUMBER field. For example: you passed 1 but there are zero status records.
Some header fields always have valid information, even if the last call didn’t end with an error or warning. For example, you can find out what the last executed SQL statement was, and how many rows it affected, even if the number of Status Records is zero.
The great majority of diagnostics are only applicable to stmt
s. You will
only need to get a dbc
's diagnostics area fields if the last call used a
dbc
handle, which usually means if the last call was connect
,
disconnect
, endtran
or some variants of allochandle
and
freehandle
. As for env
s and desc
s, they too have diagnostics
areas, but use of SQLGetDiagField
with henv
s and hdesc
s is
esoteric.
Example:
#include "sqlcli.h"
...
SQLHSTMT hstmt;
SQLINTEGER diag_number; /* gets # of status records */
SQLINTEGER row_number;
SQLCHAR sqlstate[5+1]; /* gets SQLSTATE */
SQLCHAR catalog[128+1]; /* gets a catalog name */
SQLSMALLINT catalog_octet_length;/* size of catalog name */
SQLCHAR schema[128+1]; /* gets a schema name */
SQLSMALLINT schema_octet_length; /* size of schema name */
SQLCHAR name[128+1]; /* gets an object name */
SQLSMALLINT name_octet_length; /* size of name */
...
/* Make a one-Column Table, with a CHECK Constraint. */
SQLExecDirect(hstmt,"CREATE TABLE Ts(col_1 INT,CHECK (col_1=7);",SQL_NTS);
/* Try to violate the CHECK Constraint. */
SQLExecDirect(hstmt,"INSERT INTO Ts VALUES(15);",SQL_NTS);
/* Find out how many status records are in the diagnostics area. */
SQLGetDiagField(SQL_HANDLE_STMT,NULL,SQL_DIAG_COUNT,&diag_count,NULL,NULL);
/* Loop: For each status record ... */
for (row_number=1; row_number<=diag_number; ++row_number) {
/* Get SQLSTATE. */
SQLGetDiagField(
SQL_HANDLE_HSTMT,hstmt,row_number,SQL_DIAG_SQLSTATE,sizeof(sqlstate),
sqlstate,NULL);
/* The first two octets of SQLSTATE are the error class. */
/* if class = '23' integrity constraint violation: what constraint? */
if (memcmp(sqlstate,"23",2)==0) {
/* Get Catalog . Schema . name of the Constraint */
SQLGetDiagField(
SQL_HANDLE_STMT,hstmt,row_number,SQL_DIAG_CONSTRAINT_CATALOG,catalog,
sizeof(catalog),&catalog_size);
SQLGetDiagField(
SQL_HANDLE_STMT,hstmt,row_number,SQL_DIAG_CONSTRAINT_SCHEMA,
schema,sizeof(schema),&schema_size);
SQLGetDiagField(
SQL_HANDLE_STMT,hstmt,row_number,SQL_DIAG_CONSTRAINT_NAME,
name,sizeof(name),&name_size);
} }
ODBC: The SQLGetDiagField
function is new in ODBC 3.0 (older ODBC
versions had only SQLError
for getting diagnostics fields). In addition to
all the standard options, ODBC has an additional useful-looking one:
SQL_DIAG_CURSOR_ROW_COUNT
, for getting the number of rows in an open
Cursor. (ODBC also gives row and Column number within the result set.) ODBC,
unlike standard SQL, sorts status records by row number.
SQLGetDiagRec¶
Function Prototype:
SQLRETURN SQLGetDiagRec(
SQLSMALLINT HandleType, /* 16-bit input */
SQLINTEGER Handle, /* 32-bit input */
SQLSMALLINT RecordNumber, /* 16-bit input */
SQLCHAR *Sqlstate, /* CHAR* output */
SQLINTEGER *NativeError, /* 32-bit output */
SQLCHAR *MessageText, /* CHAR* output */
SQLSMALLINT BufferLength, /* 16-bit input */
SQLSMALLINT *TextLength); /* 16-bit output */
Job: Get SQLSTATE
, sqlcode
and error-message from one status
record.
Algorithm:
If (HandleType <> SQL_HANDLE_ENV | SQL_HANDLE_DBC | SQL_HANDLE_STMT
| SQL_HANDLE_DESC)
Or (what handle references isn't the type that HandleType indicates)
return error: CLI-specific condition-invalid handle
If (RecordNumber < 1)
return error: 35000 invalid condition number -
If (RecordNumber > number of status records in diagnostics area)
/* SQLGetDiagRec returns +100, but doesn't make its own diagnostics */
/* In ODBC, some output parameters would be changed anyway. */
return error: no data -
If (SqlState is not a null pointer)
Set *SQLState = status record [RecordNumber] . SQL_DIAG_SQLSTATE
If (NativeError is not a null pointer)
Set *NativeError = status record [RecordNumber] . SQL_DIAG_NATIVE_ERROR
If (MessageText is not a null pointer)
/* ... The message text is copied in the usual Character String
Retrieval way. */
Set *MessageText = status record [RecordNumber ]. SQL_DIAG_MESSAGE_TEXT
For description of the SQL_DIAG_SQLSTATE
, SQL_DIAG_NATIVE_ERROR
, and
SQL_DIAG_MESSAGE_TEXT
fields, see the SQLGetDiagField
descriptions.
Notes:
The assumption behind
SQLGetDiagRec
is that, when you want diagnostics information, you specifically wantSQL_DIAG_SQLSTATE
,SQL_NATIVE_ERROR
andSQL_DIAG_MESSAGE_TEXT
(both contents and length). If the assumption is wrong and you want only some of these fields, or you want other fields, then you might find thatSQLGetDiagField
is all you need. We observed similar assumptions at work when we looked at thedesc
functions,SQLGetDescField
andSQLGetDescRec
.Calls to
SQLGetDiagRec
are frequent after a CLI function returns an error. That is:if (SQLfunction(...) < 0) SQLGetDiagRec(...);
is the normal way of calling.
Example: This example shows that SQLGetDiagRec
and SQLGetDiagField
may be similar. The first call retrieves dbc
's SQLSTATE
using
SQLGetDiagField
– we pass NULL
for the final 4 parameters because we
don’t care about them.
#include "sqlcli.h"
SQLCHAR sqlstate[6];
...
SQLGetDiagField(SQL_HANDLE_DBC,hdbc,1,sqlstate,sizeof(sqlstate),NULL);
SQLGetDiagRec(SQL_HANDLE_DBC,hdbc,1,sqlstate,NULL,NULL,NULL,NULL);
This example shows the minimalist error-handling procedure for applications
that are written in a hurry: if anything goes wrong, print a message and stop
the program. The symbol SQL...
means “any CLI function”. The "if
(sqlreturn < 0)"
test uses an assumption (true at the moment) that
SQL_SUCCESS
and SQL_SUCCESS_WITH_INFO
and SQL_NO_DATA
– the
non-problems – are all greater than or equal to zero; SQL_INVALID_HANDLE
and SQL_NEED_DATA
and SQL_ERROR
– the problems – are less than zero.
#include "sqlcli.h"
SQLCHAR sqlstate[5+1];
SQLCHAR sqlmessage[SQL_MAX_MESSAGE_LENGTH+1];
SQLRETURN sqlreturn;
...
sqlreturn = SQLFunc(...);
if (sqlreturn < 0) {
printf("Error: \n");
if (sqlreturn==SQL_INVALID_HANDLE) {
/* For the SQL_INVALID_HANDLE return code, there are no associated
status records. So we have to make up and display our own error. */
printf("Invalid handle.\n"); }
if (sqlreturn==SQL_NEED_DATA) {
/* This is shown for completeness; "need data" needs discussion later */
printf("Need data.\n"); }
if (sqlreturn==SQL_ERROR) {
if (SQLGetDiagRec(...,...,1,sqlstate,NULL,sqlmessage,NULL,NULL)
== SQL_NO_DATA) {
/* Read the SQLAllocEnv description for special notes about handling
errors from that function. For all other CLI functions, there
will be at least one status record, so you won't get here. */
printf("(No status rows).\n"); }
else {
printf("SQLSTATE=%s.\n",sqlstate);
printf("MESSAGE_TEXT=%s.\n",sqlmessage);
exit(1); }
This example displays warning or error messages after an execution.
#include "sqlcli.h"
SQLCHAR sqlstate[6], sqlmessage[SQL_MAX_MESSAGE_LENGTH+1];
SQLINTEGER sqlnative, sqlmore;
SQLSMALLINT sqlrecordnumber, sqlmessagelength;
SQLHSTMT hstmt;
SQLRETURN sqlreturn1, sqlreturn2;
...
sqlreturn1 = SQLExecDirect(hstmt,"SQL statement goes here",SQL_NTS);
if (sqlreturn1 == SQL_ERROR || sqlreturn1 == SQL_SUCCESS_WITH_INFO) {
for (sqlrecordnumber=1;;++sqlrecordnumber) {
sqlreturn2=SQLGetDiagRec(
SQL_HANDLE_STMT,hstmt,sqlrecordnumber,sqlstate,&sqlnative,
sql_message,sizeof(sql_message),&sql_message_length);
if (sqlreturn2 == SQL_NO_DATA || sqlreturn2 < 0) break;
printf("SQLExecDirect returned: %d\n",sqlreturn1);
printf("Status code = %s\n",sqlstate);
printf("Native code or sqlcode = %ld\n",sqlnative);
printf("Error/Warning message = %s.\n",sqlmessage);
if (sqlmessagelength>sizeof(sqlmessage) printf("May be truncated."); }
SQLGetDiagField(SQL_HANDLE_STMT,hstmt,1,SQL_DIAG_MORE,&sqlmore,NULL,NULL);
if (sqlmore) {
printf("Not all Error/Warning conditions have been displayed!\n"); }
ODBC: The SQLGetDiagRec
function is new in ODBC 3.0; applications for
earlier ODBC versions use SQLError
, which is similar. ODBC example programs
often use the names SqlState
, Msg
and rc
where we have tended to
use SQLSTATE
, sqlmessage
and sqlreturn
.
SQLError¶
Function Prototype:
SQLRETURN SQLError(
SQLHENV henv, /* 32-bit input */
SQLHDBC hdbc, /* 32-bit input */
SQLHSTMT hstmt, /* 32-bit input */
SQLCHAR *Sqlstate, /* pointer to char* output -- char[5+1] */
SQLINTEGER *NativeError, /* pointer to 32-bit output */
SQLCHAR *MessageText, /* pointer to char* output */
SQLSMALLINT BufferLength, /* 16-bit input */
SQLSMALLINT *TextLength /* pointer to 16-bit output */
);
Job: Return “diagnostics” – that is, the completion conditions (warnings)
and exception conditions (errors) that are associated with the env
or
dbc
or stmt
.
Although all standard DBMSs will support it, and although it is an official
SQL3 function, SQLError
is obsolete. The modern way to get diagnostics is
with SQLGetDiagRec
or SQLGetDiagField
.
Algorithm:
/* The diagnostics come from a stmt or (if hstmt
is 0) from a dbc or (if hdbc is also 0) from an env.
SQLError does not get diagnostics from
all three resources at once, or from a desc. */
If (hstmt <> 0)
Set Handle = hstmt
Else
/* hstmt == 0 */
If (hdbc <> 0)
Set Handle = hdbc
Else
/* hstmt == 0 and hdbc == 0 */
If (henv <> 0)
Set Handle = henv
Else
/* hstmt == 0 and hdbc == 0 and == 0 */
return error: CLI-specific condition-invalid handle
/* Now Handle == handle of stmt or dbc or env */
/* The diagnostics, if any, were created by the last CLI function
that was called using Handle. */
For (each status record generated by the last CLI function)
If (we have already called SQLError and gotten this status record)
continue
If (there are no more status records)
return SQL_NO_DATA (+100)
/* ... a DBMS that follows the ODBC requirements would set
sqlstate = '00000', NativeError = +100, before returning
SQL_NO_DATA. This is a signal to the application program that it
should break out of a loop. */
Else
break
/* We are now looking at a status record which was generated by a
previous function call using the (passed) Handle. The following
is the same as if we called:
SQLGetDiagRec (<handle type>, <Handle>, <# of status record>,
Sqlstate,NativeError, MessageText, BufferLength, TextLength) */
Return status record's SQL_DIAG_SQLSTATE value to Sqlstate.
Return status record's SQL_DIAG_MESSAGE_TEXT value to MessageText
(the return happens in the usual way for Character String Retrieval).
Return status record's SQL_DIAG_NATIVE value, presumably SQLCODE, to
NativeError.
Notes: The last five parameters of SQLError
are the same as the last
five parameters of SQLGetDiagRec
. The effective difference is that, with
SQLGetDiagRec
, you pass a RecordNumber
parameter, while with
SQLError
you depend on the DBMS to keep an internal counter – SQLError
will always retrieve the next status record.
Example:
#include "sqlcli.h"
...
SQLCHAR sqlstate[6]; /* not 5: 6!! Allow for \0 at the end! */
SQLINTEGER sqlnative; /* this is a "long int" */
SQLHSTMT hstmt;
...
sqlreturn=SQLExecDirect(hstmt,"INSERT VALUES;",SQL_NTS);
/* The above is illegal SQL so the return code will be negative */
if (sqlreturn==SQL_ERROR) goto error_handler_for_stmt;
...
error_handler_for_stmt:
/* **TRAP: sometimes errors happen for dbc or env functions too, each
type of handle needs a separate error-handling procedure. */
SQLError(0,0,hstmt,sqlstate,&sqlnative,NULL,NULL,NULL);
/* sqlstate is probably '42000' */
/* sqlnative is probably less than zero */
...
ODBC: The SQLError
function has been around since ODBC 1.0. In ODBC
3.0, it is labelled “deprecated” and ODBC’s driver manager will map it to
SQLGetDiagRec
.
SQLRowCount¶
Function Prototype:
SQLRETURN SQLRowCount(
SQLHSTMT hstmt, /* 32-bit input -- statement handle */
SQLINTEGER *RowCount /* 32-bit output */
);
Job: Find out how many rows were inserted or updated or deleted during the
execution of the last SQLExecute
or SQLExecDirect
call.
Algorithm:
If (hstmt does not refer to an executed statement)
return error: HY010 CLI-specific condition-function sequence error
Set *RowCount = stmt's diagnostics area's SQL_DIAG_ROW_COUNT value.
Notes:
The row count is the number of rows affected when you call
SQLExecute
orSQLExecDirect
, and the SQL statement you’re executing begins withINSERT
orUPDATE
orDELETE
(the SQL-data change statements).Only directly affected rows matter. If you delete one primary key row, and there are 10 foreign key rows that are also deleted because the
FOREIGN KEY
Constraint definition includesON DELETE CASCADE
, then a total of 11 rows are deleted: 1 directly, 10 indirectly – so theSQLRowCount
function returns 1.Only “searched
UPDATE
” and “searchedDELETE
” statements matter. TheUPDATE ... WHERE CURRENT OF
<Cursor> andDELETE ... WHERE CURRENT OF
<Cursor> statements have no effect on row count.With some DBMSs,
SQLRowCount
will contain the number of rows returned by the lastSELECT
statement. That’s very useful if you want to display the results on the screen along with a Windows scrollbar. If your DBMS won’t give you that, there are other options: (a) use aSELECT COUNT(*)
statement (may be unreliable in a multi-user environment, may fail if selection is of a grouped View), (b) callSQLGetDiagField
with theSQL_DIAG_CURSOR_ROW_COUNT
option (non-standard, works only with ODBC) or (c) callSQLFetchScroll
until the return isSQL_NO_DATA
.You can get the same result by calling:
SQLGetDiagField(SQL_HANDLE_STMT,hstmt,SQL_DIAG_ROW_COUNT,&RowCount,NULL,NULL);
but
SQLGetDiagField
only returns results for “the last function”, which means (for instance) that if you’ve fetched since you executed theUPDATE
statement,SQLGetDiagField
can’t tell you anything.SQLRowCount
, which returns results for “the lastSQLExecute
orSQLExecDirect
function”, is better.If the number of changed rows is zero, then
SQLExecute
andSQLExecDirect
both returnSQL_NO_DATA
(notSQL_SUCCESS
orSQL_SUCCESS_WITH_INFO
).
Example:
#include "sqlcli.h"
SQLINTEGER row_count;
...
if (SQLExecDirect(hstmt,"INSERT INTO Table_1 VALUES (1);",SQL_NTS)>=0) {
if (SQLRowCount(hstmt,&row_count)>=0) {
/* The value of row_count is 1. */ } }
ODBC: The SQLRowCount
function has been around since ODBC 1.0.
And that’s it for the diagnostic functions. Now let’s take a look at the
Standard’s SQLSTATE
codes.
SQLSTATE Codes¶
The SQL status parameter SQLSTATE
is a 5-character string value, with 2
parts: the first 2 characters represent a class value, the following 3
characters represent a subclass value. SQLSTATE
codes are limited to digits
and simple Latin upper-case letters.
Class values that begin with 0, 1, 2, 3, 4, A, B, C, D, E, F, G or H are called standard-defined classes and identify status conditions defined in either the SQL Standard or some other international standard. Subclass values associated with standard-defined classes that also begin with one of those 13 characters are called standard-defined subclasses and also identify status conditions defined in either the SQL Standard or some other international standard, while subclass values associated with standard-defined classes that begin with 5, 6, 7, 8, 9, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y or Z are called implementation-defined subclasses and identify status conditions defined by DBMS vendors.
Class values that begin with 5, 6, 7, 8, 9, I, J, K, L, M, N, O, P, Q, R, S, T,
U, V, W, X, Y or Z are called implementation-defined classes and identify
exception conditions defined by DBMS vendors. All subclass values except ‘000’
(no subclass) associated with implementation-defined classes are
implementation-defined subclasses. An implementation-defined completion
condition is identified by returning an implementation-defined subclass
together with one of the SUCCESSFUL COMPLETION
, WARNING
or NO DATA
classes.
If a subclass value is not specified for a condition, then either subclass ‘000’ or an implementation-defined subclass is returned.
If multiple conditions are returned, then your DBMS decides which condition is
the one that will be returned in the SQLSTATE
parameter. (Any number of
condition values, in addition to SQLSTATE
, may be returned in the
diagnostics area.)
Using the CLI, you can retrieve SQLSTATE
with one of the diagnostics
functions (SQLGetDiagField
, SQLGetDiagRec
or SQLError
). Using
embedded SQL, you can retrieve SQLSTATE
with GET DIAGNOSTICS
, or you
can let the DBMS fill it in automatically. Since the status codes are
reasonably standard, application programmers can anticipate what SQLSTATE
values may crop up, and they can write appropriate error-testing or descriptive
routines. The rest of this chapter contains detailed descriptions for all
SQLSTATE
s which are defined in the SQL Standard, as well as summary
information about some SQLSTATE
s which are used in common application
environments, such as ODBC.
We suggest you examine the list of SQLSTATE
codes and decide which warnings
and errors you must take specific action for. Make a case statement which will
be executed after each SQL operation. If you are programming for ODBC 3.x,
don’t worry about the obsolete ODBC 2.0 entries in the list – Microsoft’s
driver manager will translate them to the current standardized value. If you
use the list in conjunction with some vendor manual, you will probably notice
that our descriptions are more specific and detailed; however, you should
prefer the vendor’s description in case of outright contradiction. For casual
users, the DBMS’s in-context error-message displays, accompanied by a pointer
to the offending SQL statement, will suffice. But that is an “after-the-fact”
proposition. If your job is to program for errors that haven’t happened yet,
you need a complete list with some examples and explanations for every entry.
Here is an example of a tiny C program (runnable in a DOS box) with one embedded SQL statement, followed by a case statement that checks for an error:
EXEC SQL INCLUDE SQLCA; /* so error message defined here? */
EXEC SQL BEGIN DECLARE SECTION;
char sqlcode[6]; /* Notice we allow 6 characters, there's a \0 too */
EXEC SQL END DECLARE SECTION;
void main ()
{
EXEC SQL DROP TABLE x RESTRICT;
portability(sqlstate); /* Perhaps change the class */
switch (sqlstate) {
case '.....': /* Okay */
case '.....': /* Table not found */
case '.....': /* Another table depends */
default: /* All other errors */
} }
/* In a portable program you won't know what subclasses were added by each
vendor, so change all implementation-defined subclasses to '000'. NIST uses
a similar technique for its compliance-test programs. */
void portability (char sqlstate[])
{
if (sqlstate[2]>='I' || (sqlstate[2]>='4' && sqlstate[0]<='9') {
/* The third character of sqlstate, which is the first byte of subclass,
is a letter >= 'I' or is a digit >= '4' -- implementation-defined. */
sqlstate[2]=sqlstate[3]=sqlstate[4]='0'; } }/* subclass = '000' */
SUCCESSFUL COMPLETION SQLSTATEs¶
The following SQLSTATE
codes identify a successful completion condition.
00000 successful completion
The “successful completion” class identifies “completion conditions” (as opposed to “exception conditions”, which are errors). In the case of
SQLSTATE 00000
, the last SQL operation sailed through without a problem. The00000
status code is invisible to CLI programs because the Standard says: if the return code= SQL_SUCCESS
, then no status records are generated.
WARNING SQLSTATEs¶
The following SQLSTATE
codes identify a successful completion condition
with a warning.
01000 warning
The “warning” class identifies completion conditions that were processed with some type of warning. They are usually associated with some DBMS-specific informational message, which you can retrieve with
SQLGetDiagRec
orGET DIAGNOSTICS
. In the CLI, the existence of a warning diagnostic is signalled by theSQLRETURN
valueSQL_SUCCESS_WITH_INFO (1)
.SQLSTATE 01000
is the miscellaneous-warning category. For completion conditions that fit in the warning class, but don’t fit in one of the subclasses listed below (such as01001
), this is what you’ll get. Suggestion for thisSQLSTATE
: get the message withSQLGetDiagRec
, display the message and continue.01001 warning-cursor operation conflict
This
SQLSTATE
was included in the SQL-92 Standard by mistake; the corrigendum bulletin #3 says it should only be an SQL3SQLSTATE
. The NIST tests expect DBMSs to returnSQLSTATE=01001
if youDELETE
with and without a Cursor in the same transaction.01002 warning-disconnect error
There was an error during execution of the CLI function
SQLDisconnect
, but you won’t be able to see the details because theSQLDisconnect
succeeded.01003 warning-null value eliminated in set function
The set function had to ignore a
NULL
when working on its argument. For example, theSUM
of 5 andNULL
is 5 (notNULL
), but01003
warns you that the result may be inaccurate becauseNULL
usually means “unknown”.01004 warning-string data, right truncation
Happens when you try to squeeze a 5-character (or bit) value into a 4-character (or bit) space (remember that “string” can be either character or bit string). The truncation should happen for data outbound from the database to a host variable, for example in the statement
"SELECT ... INTO :x"
. It should not happen for data inbound to the database – that would be not a warning but an error (22001
).01005 warning-insufficient data item descriptor areas
Every descriptor area has multiple IDAs. You need one IDA per Column of a result set, or one per parameter. Either reduce the number of Columns in the select list or reduce the number of ?s in the SQL statement as a whole.
01006 warning-privilege not revoked
There is no Privilege descriptor for a combination of: this grantor, this grantee, this action. The DBMS does not return an error if a Privilege revocation fails – instead, it revokes whatever Privileges it can and returns this warning. If an equivalent Privilege was granted by a different grantor, it continues to exist, but warning
01006
does not appear.01007 warning-privilege not granted
Probably the grantor doesn’t hold a Privilege
WITH GRANT OPTION
. For example: Susan has theUPDATE
Privilege onTABLE_1
(without grant option) and theINSERT
Privilege onTABLE_1
(WITH GRANT OPTION
). She says:"GRANT SELECT, INSERT, UPDATE ON Table_1 TO Joe;"
. Result: Joe gets theINSERT
Privilege, but not theSELECT
orUPDATE
Privileges, hence this warning (some DBMSs will generate the warning twice because two Privileges are ungranted). Warning01007
also appears if the grantor has zero PrivilegesWITH GRANT OPTION
, and says"GRANT ALL PRIVILEGES ..."
. On the other hand, if the grantor holds zero Privileges period, the result is error42000
instead of warning01007
.01008 warning-implicit zero-bit padding
Suppose you insert
B'1'
– a one-bit binary <literal> – into a two-bit Column. The second bit will be a 0, and the DBMS will return this warning.01009 warning-search condition too long for information schema
Suppose you say “
CREATE TABLE ... CHECK
(<condition>)”, and the length of <condition> is larger than what can be stored in theINFORMATION_SCHEMA
View,CHECK_CONSTRAINTS
, in itsCHECK_CLAUSE
Column. The Table will still be created – this warning only means you won’t be able to see the entire information about the Table when you look atINFORMATION_SCHEMA
. See also:0100A
and0100B
.0100A warning-query expression too long for information schema
This is the same as warning
01009
except that instead of a search condition (as in aCHECK
clause), you’re using a query condition (usuallySELECT
). Thus, if you say"CREATE VIEW ..."
with a very long query, the size of ColumnVIEW_DEFINITION
in ViewVIEWS
inINFORMATION_SCHEMA
is a limiting factor.0100B warning-default value too long for information schema
This is the same as warning
01009
except that instead of a search condition (as in aCHECK
clause), you’re using a default value.
0100C warning-dynamic result sets returned
0100D warning-additional result sets returned
0100E warning-attempt to return too many result sets
0100F warning-fewer locators than dynamic result sets
0102F warning-array data, right truncation
01Hxx warning-external routine warning
The author of the external routine chooses the subclass value of
xx
.01S00 warning-invalid connection string attribute
(ODBC 2+3)The ODBC function
SQLBrowseConnect
orSQLDriverConnect
requires a parameter string with a certain format. Connection happens anyway.01S01 warning-error in row
(ODBC 3)With ODBC 3.x, this warning happens only for
SQLExtendedFetch
or forSQLFetchScroll
. Although an “error” has happened, this is only a warning because other rows might have been returned without error.01S02 warning-option value changed
(ODBC 3)You used an ODBC function to change an option (e.g.:
SQLSetEnvAttr
). This warns you that the change occurred.01S06 warning-attempt to fetch before the result set returned the first rowset
(ODBC 3)It would be clearer to use this wording: “attempt to fetch before the first row in the result set”. This error would be returned if your last fetch was of the first row in the result set and now you attempt to fetch
PRIOR
.01S07 warning-fractional truncation
(ODBC 3)You’ll get this error if, for example, you assigned the value 5.432 to a Column whose definition is
DECIMAL(3,2)
– that is, the scale of the target is 2 and the scale of the source is 3, so only 5.4 is stored. A problem with the non-fractional part would result in another SQLSTATE:22003
.01S08 warning-error saving file DSN
(ODBC 3)A warning from
SQLDriverConnect
. The Connection succeeds, but the file indicated by the FILEDSN keyword was not saved.01S09 warning-invalid keyword
(ODBC 3)A warning from
SQLDriverConnect
. The Connection succeeds, but theSAVEFILE
keyword was ignored.
NO DATA SQLSTATEs¶
The following SQLSTATE
codes identify a successful completion condition
where no data has been found that matches the given criteria.
02000 no data
The “data not found” class identifies completion conditions that were processed without any data that matched the given criteria being found. If the status code is class 02, then the return code will be
SQL_NO_DATA
. Most programs do not look for status records if the return code isSQL_NO_DATA
, but there is a slight chance that a warning exists. The DBMS does not make a status record forSQLSTATE 02000
, but it might make status records for implementation-defined subclasses within class 02.SQLSTATE 02000
goes together withsqlcode = +100
and return code= SQL_NO_DATA
. There are several scenarios which lead toSQLSTATE 02000
:fetches – If the Cursor position is now past the last row, or before the first row in the result set – e.g.: due to a
SQLFetchScroll(...,SQL_PRIOR,...)
call when Cursor was on first row of the result set.updates – Zero rows were affected by an
INSERT
,UPDATE
orDELETE
statement.diagnostics – No status record corresponds to the
RecordNumber
parameter.desc
functions – No item descriptor area corresponds to theRecordNumber
parameterin general – Whenever you ask for data, and there is no data.
In the CLI, the DBMS does not generate status records for
SQLSTATE=02000
. The only way to check for “no data” is to look at the return code.02001 no data-no additional result sets returned
It is possible for a
CALL
statement to produce multiple result sets, but in this case there are no more.02001
is possible if the function isSQLMoreResults
.
ERROR SQLSTATEs¶
The following SQLSTATE
codes identify an exception condition: something is
preventing an SQL statement from being successfully completed.
03000 SQL statement not yet complete
The “SQL statement not yet complete” class identifies exception conditions that relate to incomplete processing of SQL statements.
07000 dynamic SQL error
The “dynamic SQL error” class identifies exception conditions that relate to dynamic SQL processing errors.
07001 dynamic SQL error-using clause does not match dynamic parameters
You might encounter this error if you set the length of a descriptor, then
EXECUTE ... USING
<descriptor>. Often this exception results from consistency-check failure duringSQLExecute
: seeSQLSTATE HY021
. In ODBC, the name for this subclass is “wrong number of parameters”.07002 dynamic SQL error-using clause does not match target specifications
Often this exception results from consistency-check failure during
SQLExecute
: seeSQLSTATE HY021
. Sometimes this exception results from an incorrect number of parameters – but see also:SQLSTATE 07008
. In ODBC, the name for this subclass is “COUNT
field incorrect”.
07003 dynamic SQL error-cursor specification cannot be executed
07004 dynamic SQL error-using clause required for dynamic parameters
You cannot simply
EXECUTE
an SQL statement which has dynamic parameters – you also need to use aUSING
clause. See also:SQLSTATE 07007
.07005 dynamic SQL error-prepared statement not a cursor-specification
This results from an attempt to use ODBC function
SQLColAttribute
orSQLDescribeCol
for an SQL statement that returned no result set, or from using “DECLARE CURSOR
” followed by a prepare or execute of an SQL statement that does not return a result set.07006 dynamic SQL error-restricted data type attribute violation
You are using a parameter whose value does not match the <data type>; the DBMS cannot even try to
CAST
to the correct <data type> because the source and target are too different. For example, you have a host variable defined asSQLINTEGER
, you have a Column containing aTIMESTAMP
and you try to fetch that Column into the host variable. With CLI, this might mean that you forgot to re-bind the parameters when you prepared a new SQL statement.07007 dynamic SQL error-using clause required for result fields
You cannot simply
EXECUTE
an SQL statement which has result fields – you also need to use aUSING
clause. See also:SQLSTATE 07004
.07008 dynamic SQL error-invalid descriptor count
Using the embedded
SQL ALLOCATE DESCRIPTOR
statement, you allocated a 5-item descriptor. Now you are trying to use the sixth item in that descriptor. See also:SQLSTATE 07009
.07009 dynamic SQL error-invalid descriptor index
You are using a CLI descriptor function (such as
SQLBindCol
orSQLBindParameter
) and the Column number is less than 1 or greater than the maximum number of Columns. Or, you are using the embedded SQLALLOCATE DESCRIPTOR
statement with a size which is less than 1 or greater than an implementation-defined maximum. See also:SQLSTATE 07008
.07S01 dynamic SQL error-invalid use of default parameter
You used
SQLBindParameter
withSQL_DEFAULT_PARAMETER
, but now it turns out that the parameter does not have a default value.08000 connection exception
The “connection exception” class identifies exception conditions that relate to SQL-Connections.
08001 connection exception-SQL-client unable to establish SQL-connection
The client could not get in touch with the server – perhaps there is no such server or perhaps the network is busy.
08002 connection exception-connection name in use
The name of an SQL-Connection must be unique. With standard SQL, this would happen if you said “
CONNECT ... AS 'X' ...
” twice (only oneX
at a time, please).08003 connection exception-connection does not exist
You are trying to use a connection-related function (such as
SQLGetConnectAttr
) but the SQL-Connection is not open. Or, you said “DISCONNECT 'X'
” and eitherX
was never connected, or has already been disconnected. If the call isSQLAllocHandle(SQL_HANDLE_STMT,...)
,&hstmt
is set to zero. You can get diagnostics from thehdbc
.08004 connection exception-SQL-server rejected establishment of SQL-connection
You’ll get this error if, for example, the
SQLConnect
function was unsuccessful. The server might not like the password, or it might already be handling the maximum number of clients.08006 connection exception-connection failure
This occurs for a
SET CONNECTION
statement, where the argument is presumably a dormant Connection. The failure might be due to a server failure that occurred while the Connection was dormant. TheSET CONNECTION
might be implicit – for example, aDISCONNECT
statement might result in an attempt to re-establish the last dormant Connection.08007 connection exception-transaction resolution unknown
While you were trying to
COMMIT
, you were cut off. This is a bad one, because you are not told whether the transaction finished successfully or not. The ODBC manual calls this error “Connection failure during transaction” and implies that it can happen forROLLBACK
too.08S01 connection exception-communication link failure
(ODBC 2+3)This can happen during execution of pretty well any ODBC function. Perhaps there was a hiccup on a phone line.
09000 triggered action exception
The “triggered action exception” class identifies exception conditions that relate to Triggers.
0A000 feature not supported
The “feature not supported” class identifies exception conditions that relate to features you’re trying to use, but that your DBMS hasn’t implemented. The Standard does not specify what will cause this
SQLSTATE
, possibly because the expectation is that all features will be supported. If the feature is ODBC-related, see also:SQLSTATE IM001
,HYC00
.0A001 feature not supported-multiple server transactions
The meaning is “a single transaction cannot be performed on multiple servers”. Such a feature is sophisticated and rare.
0B000 invalid transaction initiation
The “invalid transaction initiation” class identifies exception conditions that relate to beginning a transaction.
0D000 invalid target type specification
The “invalid target type specification” class identifies exception conditions that relate to specifying a target for data.
0E000 invalid schema name list specification
The “invalid schema name list specification” class identifies exception conditions that relate to specifying Schema paths.
0F000 locator exception
The “locator exception” class identifies exception conditions that relate to locators:
BLOB
andCLOB
<data type>s, and their values.0F001 locator exception-invalid specification
This will be returned if a value passed for a
BLOB
orCLOB
is invalid.
0F002 locator exception-update attempted with non-updatable locator
0F003 locator exception-location does not represent specified object
0F004 locator exception-unknown native value
0G000 reference to null table value
0H000 invalid SQLSTATE value
0K000 resignal when handler not active
0K002 resignal when handler not active-modifying SQL-data not permitted
0K003 resignal when handler not active-prohibited SQL-statement attempted
0K005 resignal when handler not active-function executed no return statement
0L000 invalid grantor
0N000 most specific type mismatch in invocation of type-preserving function
0P000 invalid role specification
0Q000 source result set not created by current SQL-server
0R000 cursor already allocated to result set or procedure
20000 case not found for case statement
21000 cardinality violation
Suggested error message: “subquery contained more than one row”. For example, suppose you have a Table T, with a Column S1 and two rows. In both rows, Column S1 has the value 5. Then either “
SELECT (SELECT s1 FROM T) FROM ...
” (scalar subquery) or “... WHERE 5 = (SELECT s1 FROM T)
” (row subquery) violate cardinality. Another possibility, applicable to embedded SQL only, is that you are using a singleton-SELECT
statement format but there are two rows returned. Some cardinality violations, e.g.:OVERLAPS
operand with degree greater than 2, causeSQLSTATE=42000
instead ofSQLSTATE=21000
.21S01 cardinality violation-insert value list does not match column list
(ODBC 2+3)For example: the statement “
INSERT INTO T (a,b) VALUES (1,2,3)
” is trying to insert three values into two Columns.21S02 cardinality violation-degree of derived table does not match column list
(ODBC 2+3)For example: the SQL statement “
CREATE VIEW (a,b) AS SELECT a,b,c FROM T;
” is creating a 2-Column View for a 3-Column select.22000 data exception
The “data exception” class identifies exception conditions that relate to data errors.
22001 data exception-string data, right truncation
Suppose you try to insert a 5-character string into a Column defined as
CHAR(4)
, or suppose you use the expression “CAST (12345 AS CHAR(4))
”. No truncation actually occurs since the SQL statement fails. See also:SQLSTATE 01004
.22002 data exception-null value, no indicator parameter
Suggested error message: “
NULL
seen, host program passed no indicator”. For example, you usedSQLBindCol
, but passed no parameter for an indicator value to be returned to. This is not an error unless you fetch aNULL
.22003 data exception-numeric value out of range
Suggested error message: “the numeric value <> is too big to fit in the target <>”. Often this is the result of an arithmetic overflow – for example, “
UPDATE ... SET SMALLINT_COLUMN = 9999999999
”, or you’re trying to retrieve a value of 5 billion into a host variable defined in Pascal as “Word”. Fractional truncation won’t cause this error, seeSQLSTATE 01S07
.
22004 data exception-null value not allowed
22005 data exception-error in assignment
For
GET DESCRIPTOR
andSET DESCRIPTOR
statements, where the <data type> and size indicated in the descriptor does not match the value, this error appears.22006 data exception-invalid interval format
For example, a year-month interval should contain only a year integer, a ‘-‘ separator, and a month integer. See also:
SQLSTATE 22015
.22007 data exception-invalid datetime format
Suggested message: “For the <data type> <>, <> is not a valid value”. This error only occurs if there is an explicit or implicit
CAST
to a datetime (date or time or timestamp). See also:SQLSTATE 22008
,22018
.22008 data exception-datetime field overflow
Suggested message: “For the data type <>, <> is not a valid value”. One thing to look for: arithmetic which causes the
DAY
field of a date to be greater than the last day of the month – for exampleDATE '1994-03-31' + INTERVAL '01' MONTH
. See also:SQLSTATE 22007
.22009 data exception-invalid time zone displacement value
Suggested message: “The time zone displacement value <> is outside the range -12:59 to 13:00”. This could happen for
SET LOCAL TIME ZONE INTERVAL '22:00' HOUR TO MINUTE;
, or forTIMESTAMP '1994-01-01 02:00:00+10:00'
. (In the latter case, it is the result of the calculation that is a problem.)
2200A data exception-null value in reference target
2200B data exception-escape character conflict
2200C data exception-invalid use of escape character
2200D data exception-invalid escape octet
22010 data exception-invalid indicator parameter value
The value of the indicator variable is less than zero but is not equal to -1 (
SQL_NULL_DATA
).22011 data exception-substring error
Suggested message: “The maximum length of
SUBSTRING
parameter is <>”. For example, “... SUBSTRING (string_column FROM 5 FOR 100) ...
” when the length ofSTRING_COLUMN
is only 1.22012 data exception-division by zero
For example: “
... column_name / ? ...
”, where?
is a parameter marker, and the value of the parameter at run time is 0. If the Column containsNULL
, then the result isNULL
– the Standard makes it clear that dividingNULL
by zero is not an error.
22014 data exception-invalid update value
22015 data exception-interval field overflow
Suggested message: “The <> field contains <>, the maximum is <>”. For example, “
... DATE '1993-01-01' + INTERVAL '1000' YEAR ...
” (this is a tricky one – the default size of all interval fields including year fields is only 2 digits). See also:SQLSTATE 22006
.22018 data exception-invalid character value for cast
Suggested message: “The character <> cannot be used when
CAST``ing to data type <>". For example, if you try to cast ``'1994/10/10'
to a date, it won’t work because the separator is ‘/’ (the correct separator is ‘-‘).22019 data exception-invalid escape character
Suggested message: “The
LIKE
escape value <> is longer than 1 character”. The expression “... LIKE '...' ESCAPE 'AB' ...
” would return this error.
2201B data exception-invalid regular expression
2201C data exception-null row not permitted in table
22020 data exception-invalid limit value
22021 data exception-character not in repertoire
Suggested message: “The character <> is not in the repertoire of Character set <>”. For example, the Character set
SQL_CHARACTER
does not contain the tilde (~), so this <literal> is not allowed: “... _SQL_CHARACTER '~' ...
”.22022 data exception-indicator overflow
Suggested message: “indicator is too small for size value <>”. This could happen if you use embedded SQL and you define the indicator as a C “short int” or Pascal “Word”. If you use ODBC, then the message won’t happen because all indicators must be 32-bit.
22023 data exception-invalid parameter value
22024 data exception-unterminated C string
Suggested message: “the C parameter string starting with <> is too long”. For example, an SQL statement uses a
?
parameter, for a string, but at runtime it is seen that the C char-string does not have a terminating'\0'
. The DBMS can only detect this error if it knows what the maximum string size is, i.e.: only in embedded SQL. Usually this problem will appear as a too-long or improperly-formatted string, so several otherSQLSTATE
error returns are possible – for example.SQLSTATE 22019
.22025 data exception-invalid escape sequence
Suggested message: “
LIKE
pattern <> has invalid escape sequence <>”. If you use an escape character, it must be followed in the pattern by _ or % or another escape character. If you use “... LIKE 'X%@' ESCAPE '@' ...
”, you’ll get this error.22026 data exception-string data, length mismatch
With ODBC this error should only occur for
SQL_LONGVARCHAR
orSQL_LONGVARBINARY
strings. For standard SQL, this error should only occur for bit strings.22027 data exception-trim error
Suggested message: “the
TRIM
string <> is longer than 1 character”. For example, “... TRIM('AB' FROM '...') ...
” results in this error.
22028 data exception-row already exists
2202C data exception-sublist error
2202D data exception-null instance used in mutator function
2202E data exception-array element error
2202F data exception-array data, right truncation
23000 integrity constraint violation
The “integrity constraint violation” class identifies exception conditions that relate to Constraint violations. Suggested message for
SQLSTATE 23000
: “Attempted violation of constraint <>”. For example, Table T has aPRIMARY KEY
Constraint and you attempt to insert two rows into T, both with precisely the same values in all Columns. For SQL-92, thisSQLSTATE
applies to attempted violations of any kind of Constraint, includingNOT NULL
s andFOREIGN KEY
Constraints. The message can also occur if the total length of a foreign key Column list is exceeded. See also:SQLSTATE 40002
.
23001 integrity constraint violation-restrict violation
24000 invalid cursor state
The “invalid cursor state” class identifies exception conditions that relate to Cursors. For
SQLSTATE 24000
, the Cursor-related operation can’t happen because some preliminary function hasn’t been called or hasn’t been completed – for example:OPEN
<Cursor>, then immediately try toOPEN
<Cursor> again.FETCH
without opening the Cursor.OPEN
<Cursor>, forget toFETCH
, thenDELETE ... WHERE CURRENT OF
<Cursor>.
For CLI programs, the DBMS returns
SQLSTATE=24000
if you try toFETCH
and there is no result set (for example, because the previous SQL statement wasINSERT
). However, if there was no previous SQL statement at all, then the return is not24000
butHY010
(CLI-specific error-function sequence error).25000 invalid transaction state
The “invalid transaction state” class identifies exception conditions that relate to transactions. For
SQLSTATE 25000
, you are most likely trying to execute an SQL statement that can only be executed at transaction start – for example you are issuing aSET SESSION AUTHORIZATION
statement after selecting something. Alternatively, you specifiedSET TRANSACTION READ ONLY
and now you are sayingUPDATE
,DROP
, etc. Finally, it is possible you are sayingINSERT
after aFETCH
.25001 invalid transaction state-active SQL-transaction
START TRANSACTION
orDISCONNECT
orSET SESSION AUTHORIZATION
orSET ROLE
statements cannot be issued if a transaction has already been started.25002 invalid transaction state-branch transaction already active
SET TRANSACTION LOCAL ...
, which applies only in multiple-server contexts, is illegal if a local transaction is already happening.
25003 invalid transaction state-inappropriate access mode for branch
transaction
25004 invalid transaction state-inappropriate isolation level for branch
transaction
25005 invalid transaction state-no active SQL-transaction for branch
transaction
25006 invalid transaction state-read-only SQL-transaction
25007 invalid transaction state-schema and data statement mixing not supported
Some DBMSs do not allow SQL-Schema statements (such as
CREATE
) to be mixed with SQL-data statements (such asINSERT
) in the same transaction.25008 invalid transaction state-held cursor requires same isolation level
The
SET TRANSACTION
statement cannot be used to change isolation level if there is a held Cursor made with a different isolation level left over from the last transaction.25S01 invalid transaction state-transaction state unknown
(ODBC 3)The attempt to end the transaction (with
SQLEndTran
) failed for at least one of the environment’s Connections.25S02 invalid transaction state-transaction is still active
(ODBC 3)The attempt to end the transaction (with
SQLEndTran
) failed; the transaction did not end (that is, the transaction is not rolled back).25S03 invalid transaction state-transaction is rolled back
(ODBC 3)The attempt to end the transaction (with
SQLEndTran
) failed; the transaction is rolled back (that is, the transaction ended).26000 invalid SQL statement name
Probable cause: you failed to
PREPARE
an SQL statement and now you are trying toEXECUTE
it.27000 triggered data change violation
With SQL-92, you can cause this error with interlocked
FOREIGN KEY
Constraints thatCASCADE ON UPDATE
, so that when youUPDATE
row#1 inTABLE#1
, it causes anUPDATE
to row#2 inTABLE#2
, which in turn causes anUPDATE
to row#1 inTABLE#1
– and that’s an error because the Standard doesn’t allow this kind of looping. With SQL3, this error can also happen for Triggers. See also:SQLSTATE 09000
,40004
.28000 invalid authorization specification
This error is caused by an invalid <AuthorizationID>. For example, “
SET SESSION AUTHORIZATION 'PUBLIC'
” is illegal because'PUBLIC'
has a special significance in SQL. It’s implementation-defined whether this can happen due to an entry of the wrong password.2A000 direct SQL syntax error access or rule violation
This error does not appear in ordinary programs.
2B000 dependent privilege descriptors still exist
You used “
REVOKE GRANT OPTION FOR
”, but notCASCADE
.2C000 invalid character set name
Presumably an invalid <Character set name> would be one that begins with a digit, contains a non-Latin letter, etc.
2D000 invalid transaction termination
Has to do with savepoints and atomicity of transactions. Should not be a matter of concern until SQL3 gets going.
2E000 invalid connection name
For a
CONNECT
statement, the argument must be a valid <identifier>.2F000 SQL routine exception
An SQL routine is a procedure or function which is written in SQL.
SQLSTATE
class2F
identifies exception conditions that relate to SQL routines. (Exceptions for non-SQL routines are class38
.)2F002 SQL routine exception-modifying SQL-data not permitted
The probable cause of this error is that the
CREATE PROCEDURE
orCREATE FUNCTION
statement contained the clause:CONTAINS SQL
orREADS SQL
, but the function contains an SQL statement which can modify the database (for example, anUPDATE
statement). The corresponding external-routine exception is38002
.2F003 SQL routine exception-prohibited SQL-statement attempted
The prohibited procedural SQL statements are the SQL-transaction statements (
START TRANSACTION
,SET TRANSACTION
,SET CONSTRAINTS
,CREATE SAVEPOINT
,RELEASE SAVEPOINT
,COMMIT
,ROLLBACK
) or the SQL-Connection statements (CONNECT
,SET CONNECTION
,DISCONNECT
) or the SQL-Schema statements (CREATE
,DROP
,ALTER
,GRANT
,REVOKE
). The corresponding external-routine exception is38003
.2F004 SQL routine exception-reading SQL-data not permitted
The probable cause of this error is that the
CREATE PROCEDURE
orCREATE FUNCTION
statement contains the clause:CONTAINS SQL
, but the function contains an SQL statement which reads the database (for example, aSELECT
statement). The corresponding SQL-routine exception is38004
.
2F005 SQL routine exception-function executed no return statement
30000 invalid SQL statement
31000 invalid target specification value
33000 invalid SQL descriptor name
If, in embedded SQL, you use “
EXECUTE ... USING DESCRIPTOR 'X';
”, a descriptor namedX
must exist.34000 invalid cursor name
If the function is
SQLSetCursorName
, then the problem is that a <Cursor name> must be a unique, valid <identifier>. If the function isSQLPrepare
orSQLExecDirect
, the SQL statement is “UPDATE ... WHERE CURRENT OF
<Cursor>” or “DELETE ... WHERE CURRENT OF
<Cursor>” and <Cursor> is not the name of an open Cursor.35000 invalid condition number
With embedded SQL, you get this by saying “
GET DIAGNOSTICS EXCEPTION 0
”. With the CLI, you get this by callingSQLGetDiagRec
orSQLGetDiagField
with aRecordNumber
parameter less than 1. IfRecordNumber
is greater than the number of status records, you don’t get this error. Instead, you get anSQL_NO_DATA
return code.36000 cursor sensitivity exception
The “cursor sensitivity exception” class identifies exception conditions that relate to Cursors and their sensitivity attribute.
36001 cursor sensitivity exception-request rejected
An attempt was made to open a sensitive Cursor, but the DBMS cannot guarantee that data changes will be visible throughout the transaction.
36002 cursor sensitivity exception-request failed
For example, an attempt was made to execute a positioned
DELETE
statement, but there is a sensitive Cursor open, and (for some implementation-dependent reason) the effects of theDELETE
cannot be made visible via that Cursor.37000 dynamic SQL syntax error or access rule violation
The SQL-92 Standard originally mentioned this
SQLSTATE
, but according to a later correction (corrigendum bulletin #3) we should useSQLSTATE = 42000
instead. That is what all ODBC 3.x drivers do.38000 external routine exception
An external routine is a procedure or function which is written in a language other than SQL.
SQLSTATE
class38
identifies exception conditions that relate to external routines. (Exceptions from SQL routines are class2F
.)38001 external routine exception-containing SQL not permitted
The probable cause is that the
CREATE PROCEDURE
orCREATE FUNCTION
statement contained the clause:NO SQL
, but the routine contains an SQL statement.38002 external routine exception-modifying SQL-data not permitted
The probable cause is that the
CREATE PROCEDURE
orCREATE FUNCTION
statement contained the clause:NO SQL
orCONTAINS SQL
orREADS SQL
, but the function contains an SQL statement which can modify the database (for example, anUPDATE
statement).38003 external routine exception-prohibited SQL-statement attempted
The prohibited procedural SQL statements are the SQL-transaction statements (
START TRANSACTION
,SET TRANSACTION
,SET CONSTRAINTS
,CREATE SAVEPOINT
,RELEASE SAVEPOINT
,COMMIT
,ROLLBACK
) or the SQL-Connection statements (CONNECT
,SET CONNECTION
,DISCONNECT
) or the SQL-Schema statements (CREATE
,DROP
,ALTER
,GRANT
,REVOKE
).38004 external routine exception-reading SQL-data not permitted
The probable cause is that the
CREATE PROCEDURE
orCREATE FUNCTION
statement contained the clause:NO SQL
orCONTAINS SQL
, but the function contains an SQL statement which reads the database (for example, aSELECT
statement).
39000 external routine invocation exception
39001 external routine invocation exception-invalid sqlstate returned
39004 external routine invocation exception-null value not allowed
3B000 savepoint exception
3B001 savepoint exception-invalid specification
3B002 savepoint exception-too many
3C000 ambiguous cursor name
A more appropriate wording is: duplicate <Cursor name>. In ODBC you can get this by calling
SQLSetCursorName
with an argument that is the name of an already-open Cursor.3D000 invalid catalog name
Presumably a <Catalog name> could be invalid if it is used as a qualifier or as the argument of
SET CATALOG
, and does not refer to an existing Catalog or is not a valid <identifier>. However, all those situations are equally covered bySQLSTATE=42000
(syntax error or access violation). ForSQLSetConnectAttr
, the problem is with aSQL_ATTR_CURRENT_CATALOG
specification.3F000 invalid schema name
Presumably a <Schema name> could be invalid if it is used as a qualifier or as the argument of
SET SCHEMA
, and does not refer to an existing Schema or is not a valid <identifier>. However, all those situations are equally covered bySQLSTATE=42000
(syntax error or access violation).
3G000 invalid UDT instance
40000 transaction rollback
40001 transaction rollback-serialization failure
Two SQL jobs are running simultaneously, and a concurrency problem arose. For example, using a locking protocol, there was a deadlock or, using a timestamp protocol, a younger job has read the Object.
40002 transaction rollback-integrity constraint violation
This occurs for
COMMIT
, if there were deferred Constraints (deferred Constraints aren’t checked untilCOMMIT
time unlessSET CONSTRAINTS IMMEDIATE
is executed). So: you asked forCOMMIT
, and what you got wasROLLBACK
. See also:SQLSTATE 23000
.40003 transaction rollback-statement completion unknown
The SQL-Connection was lost during execution of an SQL statement.
40004 transaction rollback-triggered action exception
This occurs for
COMMIT
, if there was a deferred Constraint – presumably aFOREIGN KEY
Constraint unless Triggers are supported by the DBMS – and there was an attempt to violate the Constraint. See also:SQLSTATE 09000
,27000
.42000 syntax error or access rule violation
The favourite exception. Syntax errors include not just grammar or spelling errors, but “bind problems” such as failure to find an Object. Access violations are due to lack of Privileges. A high security DBMS will try to hide from the user whether the problem is “you don’t have access to
X
” as opposed to “X
isn’t there”; that’s why these two different categories are lumped together in oneSQLSTATE
(thus users can’t discover what the <Table name>s are by trying out all the possibilities).Caution
It’s easy to think that a syntax violation will always be caught during the prepare stage. Not so. Many DBMSs don’t bind until the execution stage. You have to check after both
SQLPrepare
andSQLExecute
, and perhaps even afterSQLFetch
(because a DBMS may evaluate expressions in the select list atFETCH
time, or a Column might have been dropped since the Cursor was opened).42S01 syntax error or access rule violation-base table or view already exists
(ODBC 3)This is caused by something like “
CREATE TABLE T ...
” when there’s already a Table named T.42S02 syntax error or access rule violation-base table or view not found
(ODBC 3)This is caused by something like “
SELECT * FROM T;
” when there’s no Table named T.42S11 syntax error or access rule violation-index already exists
(ODBC 3)This is caused by something like “
CREATE INDEX I ON T(c);
” when there’s already an index named I.42S12 syntax error or access rule violation-index not found
(ODBC 3)This is caused by something like “
DROP INDEX I;
” when there’s no index named I.42S21 syntax error or access rule violation-column already exists
(ODBC 3)This is caused by something like “
ALTER TABLE T ADD COLUMN c ...
” when Column C already exists.42S22 syntax error or access rule violation-column not found
(ODBC 3)This is caused by something like “
SELECT c FROM T;
” when Table T has no Column named C.44000 with check option violation
This is caused by something like “
CREATE VIEW V AS SELECT x FROM T WHERE x=5 WITH CHECK OPTION;
” then “UPDATE V SET x = 6;
”. The View’sWITH CHECK OPTION
clause is violated by the attemptedUPDATE
, which fails.
45000 unhandled user-defined exception
70100 operation aborted
(ODBC 2)Possible because tasks or threads can be destroyed in some operating systems, but don’t expect to see this.
H1zzz SQL Multimedia part 1
H2zzz SQL Multimedia part 2
H3zzz SQL Multimedia part 3
H4zzz SQL Multimedia part 4
H5zzz SQL Multimedia part 5
H6zzz SQL Multimedia part 6
H7zzz SQL Multimedia part 7
H8zzz SQL Multimedia part 8
H9zzz SQL Multimedia part 9
HAzzz SQL Multimedia part 10
HBzzz SQL Multimedia part 11
HCzzz SQL Multimedia part 12
HDzzz SQL Multimedia part 13
HEzzz SQL Multimedia part 14
HFzzz SQL Multimedia part 15
HY000 CLI-specific condition-invalid handle
CLI-specific condition-dynamic parameter value needed
There is no status record for the invalid-handle exception. The return from the CLI function is -2 (
SQL_INVALID_HANDLE
), so the only test for invalid-handle is:if (sqlreturn == SQL_INVALID_HANDLE) ...
The “invalid handle” exception occurs if (a) the passed
hstmt
orhdbc
orhenv
orhdesc
is not a handle of any resource at all or (b) the passed handle refers to the wrong type of resource, for example you passed ahdesc
but ahdbc
was expected in this context.There is no status record for the need-data exception either. The return from the CLI function is +99 (
SQL_NEED_DATA
), so the only test for need-data is:if (sqlreturn == SQL_NEED_DATA) ...
This exception is associated with deferred parameters.
HY001 CLI-specific condition-memory allocation error
Probable cause: a malloc failure. One possible solution is to close all other windows. If
SQLAllocHandle(ENVIRONMENT HANDLE ...)
: the DBMS returns 0 to&henv
. Since there is no valid handle, you can’t get diagnostics. IfSQLAllocHandle(CONNECTION HANDLE ...)
: the DBMS returns 0 to&hdbc
. You can get diagnostics using thehenv
.
HY002 CLI-specific condition-link-to-result-sets attribute precludes using this routine
HY003 CLI-specific condition-invalid data type in application descriptor
Actually, the invalid <data type> is not in an application descriptor, but in the parameter of a CLI function (
SQLBindCol
,SQLBindParameter
,SQLGetData
,SQLGetParamData
).HY004 CLI-specific condition-invalid data type
The
SQLGetTypeInfo
function requires aDataType
parameter whose value is eitherSQL_ALL_TYPES
or one of the “concise type” codes. If theDataType
parameter has an invalid value, you get this error.SQLSetDescField
andSQLBindParameter
parameters must also contain “concise type” codes.HY007 CLI-specific condition-associated statement is not prepared
A function (for example
SQLGetDescField
) requires a descriptor field, but the SQL statement has not been prepared so no description exists.HY008 CLI-specific condition-operation cancelled
Many functions can operate asynchronously. Such operations can be cancelled using the
SQLCancel
function. That’s what happened to this one.HY009 CLI-specific condition-invalid use of null pointer
One of the parameters for a function is a pointer (address). The passed pointer (address) is 0000:0000, which isn’t acceptable. Some DBMSs will return this error if they detect that the host language can’t handle pointers.
HY010 CLI-specific condition-function sequence error
Some functions won’t work unless some other function has successfully executed. For example, it’s impossible to “fetch” if you’ve never connected or selected. Or, an asynchronously executing function has not finished. Or, the last
SQLExecDirect
orSQLExecDirect
call returnedSQL_NEED_DATA
(meaning the SQL statement has not finished executing), and you’re trying to free thestmt
. See also:SQLSTATE 24000
.HY011 CLI-specific condition-attribute cannot be set now
Some settings cannot be changed in the middle of a transaction. For example, you can’t call the function
SQLSetConnectAttr
to changeSQL_ATTR_TXN_ISOLATION
, after you’ve already done some inserts.HY012 CLI-specific condition-invalid transaction operation code
For the function
SQLEndTran
, the only possible arguments areSQL_COMMIT
andSQL_ROLLBACK
.HY013 CLI-specific condition-memory management error
Many functions can return this. Usually the reason is “low memory conditions”.
HY014 CLI-specific condition-Limit on number of handles exceeded
This can come from a routine that allocates a handle (
env
,dbc
,stmt
,desc
) such asSQLAllocHandle
. The maximum number of handles is implementation-defined for each type.If
SQLAllocHandle(SQL_HANDLE_ENV,NULL,&henv)
: the DBMS puts a handle in&henv
despite the error; however, the handle is just a skeleton – you won’t be able to use it to allocate a connection handle with.If
SQLAllocHandle(SQL_HANDLE_DBC,henv,&hdbc)
: the DBMS puts 0 in&hdbc
(SQL_NULL_HDBC
). You can get diagnostics using thehenv
.If
SQLAllocHandle(SQL_HANDLE_STMT,hdbc,&hstmt)
: the DBMS puts 0 in&hstmt
(SQL_NULL_HSTMT
). You can get diagnostics using thehdbc
.If
SQLAllocHandle(SQL_HANDLE_DESC,hdbc,&hdesc)
: the DBMS puts 0 in&hdesc
(SQL_NULL_HDESC
). You can get diagnostics using thehdbc
.
HY015 CLI-specific condition-no cursor name available
Obsolete – happens only for ODBC 2.x drivers, when you call
SQLGetCursorName
.HY016 CLI-specific condition-cannot modify an implementation row descriptor
The target of a function (for example
SQLCopyDesc
) was an IRD, which can’t be changed.HY017 CLI-specific condition-invalid use of an automatically allocated descriptor handle
An attempt was made to free or change a descriptor which was not made by the application program.
HY018 CLI-specific condition-Server declined cancel request
The ODBC function
SQLCancel
was called; it’s up to the data source to decide whether this can be processed. For example, the data source might not be responding to the driver manager’s requests.HY019 CLI-specific condition-non-character and non-binary data sent in pie ces
The function
SQLPutData
was called twice for the same parameter or Column; this is only allowed for character and binary data.HY020 CLI-specific condition-attempt to concatenate a null value
The function
SQLPutData
was called twice for the same parameter or Column; in one of the calls, the passed value wasNULL
.HY021 CLI-specific condition-Inconsistent descriptor information
The fields of a
desc
have failed the consistency check. For example, theSQL_DESC_SCALE
value is greater than theSQL_DESC_PRECISION
value (for aDECIMAL
field) or theSQL_DESC_TYPE
value isSQL_DATETIME
but theSQL_DESC_INTERVAL_CODE
value is 6 (only 1 to 5 would be legal). This error happens only for the function callsSQLSetDescField
andSQLSetDescRec
. For other functions, inconsistency causesSQLSTATE 07001
or07002
.HY024 CLI-specific condition-invalid attribute value
One of the “attribute” functions was called (
SQLGetEnvAttr
,SQLSetEnvAttr
,SQLGetConnectAttr
,SQLSetConnectAttr
,SQLGetStmtAttr
,SQLSetStmtAttr
). The numeric value for the attribute parameter for this function is not defined.
HY055 CLI-specific condition-non-string data cannot be used with string
routine
HY090 CLI-specific condition-invalid string length or buffer length
You called any CLI function that passes a string value. The size parameter for this string value was less than or equal to zero, and was not equal to -3 (
SQL_NTS
).HY091 CLI-specific condition-invalid descriptor field identifier
A descriptor is a structure with information about a selected Column (in a result set); a field in that descriptor is usually identified by a numeric code; the number you used was out of bounds. For example, you can’t call
SQLColAttribute
with a field identifier parameter = 0.HY092 CLI-specific condition-invalid attribute/option identifier
You called any CLI function that passes an option number (for example
SQLGetConnectAttr
). The value you passed was not one of the defined values.HY095 CLI-specific condition-Function type out of range
(ODBC 3)The
SQLGetFunctions
function was called, with aFunctionId
parameter, the value of which is not defined for ODBC. ThisSQLSTATE
is not mentioned in the SQL3 Standard.HY103 CLI-specific condition-invalid retrieval code
(ODBC 3)The ODBC function
SQLDataSources
orSQLDrivers
was called, with aDirection
parameter, the value of which does not equalSQL_FETCH_FIRST
,SQL_FETCH_NEXT
, etc.HY104 CLI-specific condition-invalid precision or scale value
The maximum precision or scale for some <data type>s is up to the data source (i.e. sometimes the driver can’t handle big things), so the
SQLBindParameter
function gets this return. Try querying the data source to find out what its maxima are.HY105 CLI-specific condition-invalid parameter mode
The function call (e.g.:
SQLBindParameter
) contains anInputOutputMode
parameter, the value of which is not one of:SQL_PARAM_MODE_IN
,SQL_PARAM_MODE_OUT
,SQL_PARAM_MODE_INOUT
.HY106 CLI-specific condition-invalid fetch orientation
Only certain fetch “orientations” are allowed (e.g.:
NEXT
,FIRST
,LAST
,PRIOR
,ABSOLUTE
,RELATIVE
). The value you passed wasn’t one of them, for the functionSQLFetchScroll
. Or, if the Cursor isn’t aSCROLL
Cursor, the only legal orientation isNEXT
. ODBC variations: this could also happen forSQLExtendedFetch
, and the name for thisSQLSTATE
is: Fetch type out of range.HY107 CLI-specific condition-Row value out of range
One of the ODBC “fetch” or “set position” functions was called (e.g.:
SQLFetch
) and the Cursor is “key set driven”, but the row involved isn’t in the key set’s range.HY109 CLI-specific condition-invalid cursor position
A row could not be fetched, probably because it has been deleted or because it is now locked.
HY110 CLI-specific condition-invalid driver completion
(ODBC 3)The ODBC function
SQLDriverConnect
contains aDriverCompletion
parameter, the value of which is not defined for ODBC. ThisSQLSTATE
is not mentioned in the SQL Standard.HY111 CLI-specific condition-invalid bookmark value
(ODBC 3)The ODBC function
SQLExtendedFetch
orSQLFetchScroll
was called, with aFetchOrientation
parameter, the value of which was not defined for ODBC, or was a null pointer. ThisSQLSTATE
is not mentioned in the SQL Standard.HYC00 CLI-specific condition-optional feature not implemented
(ODBC 3)Many of the ODBC functions have optional features. It is unlikely that any driver will support every optional feature. When the driver doesn’t, this is the error you’ll get. See also:
SQLSTATE 0A000
(which applies to unimplemented features outside the CLI) andSQLSTATE IM001
(which applies to unsupported ODBC functions rather than features). The ODBC manual refers toHYC00
as “particularly significant”.HYT00 CLI-specific condition-timeout expired
(ODBC 3)You can specify a timeout value in milliseconds (with the
SQLSetStmtAttr
ODBC function call). If the timeout value that you set goes by and the statement is unfinished, this return happens.HYT01 CLI-specific condition-connection timeout expired
(ODBC 3)This is similar to
HYT00
, but it applies to the connection rather than to the statement.HZzzz Remote Database Access
The Remote Database Access standard, ISO/IEC 9579-2, defines several subclass code values which may be passed on via SQL, but are not defined within SQL. These will all be in the class HZ.
IM001 driver does not support this function
(ODBC 2+3)There are a lot of ODBC functions. Some drivers don’t support them all, especially since ODBC 3.x is still new (and Microsoft keeps changing it). So this error comes from the driver. Compare
SQLSTATE HYC00
.IM002 Data source name not found and no default driver specified
(ODBC 2+3)This happens when you’re connecting with ODBC, and there’s no DSN registered.
IM003 specified driver could not be loaded
(ODBC 2+3)Possibly the driver’s DLL is missing, or is not in the directory that the driver manager is searching.
IM004 driver's SQLAllocHandle on SQL_HANDLE_ENV failed
(ODBC 2+3)Usually this would indicate low memory, or that the maximum number of handles is exceeded, or a problem with function sequence.
IM005 driver's SQLAllocHandle on SQL_HANDLE_DBC failed
(ODBC 2+3)Usually this would indicate low memory, or that the maximum number of handles is exceeded, or a problem with function sequence.
IM006 driver's SQLSetConnectAttr failed
(ODBC 2+3)A connection error (during
SQLBrowseConnect
orSQLConnect
orSQLDriverConnect
).IM007 no data source or driver specified; dialog prohibited
(ODBC 2+3)An error return from the ODBC function call
SQLDriverConnect
.IM008 dialog failed
(ODBC 2+3)The
SQLDriverConnect
function puts up a dialog box; presumably the user did not end with “OK”.IM009 unable to load translation DLL
(ODBC 2+3)A failure during connect or during
SQLSetConnectAttr
, probably due to a missing DLL, which may indicate an installation error.IM010 data source name too long
(ODBC 3)The ODBC connection functions (
SQLBrowseConnect
orSQLConnect
orSQLDriverConnect
) have a maximum size for the name of the data source (DSN). You’ve exceeded it.IM011 driver name too long
(ODBC 3)The
SQLBrowseConnect
andSQLDriverConnect
functions have a maximum size for the name of the driver. You’ve exceeded it.IM012 driver keyword syntax error
(ODBC 3)The
SQLBrowseConnect
orSQLDriverConnect
functions require data in a fixed format.IM013 trace file error
(ODBC 3)Couldn’t perform an operation on the trace file, perhaps a failure to write because of a disk-full situation.
IM014 invalid name of file DSN
(ODBC 3)The
SQLDriverConnect
function requires a valid identifier.IM015 corrupt file data source
(ODBC 3)The
SQLDriverConnect
function can’t read the file.
OH000 invalid SQLSTATE value
OK000 resignal when handler not active
And that’s it for CLI diagnostics. In the next chapter, we’ll take a look at some general functions.