5 Oracle Database ODBC Driver for Programmers
The chapter is intended for programmers who want to develop robust ODBC applications using the Oracle Database ODBC driver.
Topics:
- Format of the Connection String
- SQLDriverConnect Implementation
- Reducing Lock Timeout in a Program
- Linking with odbc32.lib (Windows) or libodbc.so (UNIX)
- Information about ROWID
- ROWID in a WHERE Clause
- Enabling Result Sets
- Enabling EXEC Syntax
- Enabling Event Notification for Connection Failures in an Oracle RAC Environment
- Using Implicit Results Feature through ODBC
- About Supporting Oracle TIMESTAMP WITH TIME ZONE and TIMESTAMP WITH LOCAL TIME ZONE Column Type in ODBC
- About the Effect of Setting ORA_SDTZ in Oracle Clients (OCI, SQL*Plus, Oracle Database ODBC Driver, and Others)
Describes the effect of setting the system variableORA_SDTZ
in Oracle Clients.
5.1 Format of the Connection String
The following table describes keywords that can be included in the connection string argument of the SQLDriverConnect
function call. Missing keywords are read from the Administrator entry for the data source. Values specified in the connection string override those contained in the Administrator entry. See the Microsoft ODBC 3.52 Software Development Kit and Programmer's Reference for more information about the SQLDriverConnect
function.
Table 5-1 Keywords that Can Be Included in the Connection String Argument of the SQLDriverConnect Function Call
Keyword | Meaning | Comments |
---|---|---|
DSN |
ODBC Data Source Name |
User-supplied name. |
DBQ |
TNS Service Name |
User-supplied name. |
UID |
User ID or User Name |
User-supplied name. |
PWD |
Password |
User-supplied password. Specify PWD=; for an empty password. |
DBA |
Database Attribute |
W=write access. R=read-only access. |
APA |
Applications Attributes |
T=Thread Safety Enabled. F=Thread Safety Disabled. |
RST |
Result Sets |
T=Result Sets Enabled. F=Result Sets Disabled. |
QTO |
Query Timeout Option |
T=Query Timeout Enabled. F=Query Timeout Disabled. |
CSR |
Close Cursor |
T=Close Cursor Enabled. F=Close Cursor Disabled. |
BNF |
Bind |
T=Bind F=Bind |
DRH |
Disable Rule Hint |
T=Disable Rule Hint. F=Enable Rule Hint. |
BAM |
Batch Autocommit Mode |
IfAllSuccessful=Commit only if all statements are successful (old behavior). UpToFirstFailure=Commit up to first failing statement (V7 ODBC behavior). AllSuccessful=Commit all successful statements (only when connected to an Oracle database; against other databases, same behavior as V7). |
FBS |
Fetch Buffer Size |
User-supplied numeric value (specify a value in bytes of 0 or greater). The default is 60,000 bytes. |
FEN |
Failover |
T=Failover Enabled. F=Failover Disabled. |
FRC |
Failover Retry Count |
User-supplied numeric value. The default is 10. |
FDL |
Failover Delay |
User-supplied numeric value. The default is 10. |
LOB |
LOB Writes |
T=LOBs Enabled. F=LOBs Disabled. |
MTS |
Microsoft Transaction Server Support |
T=Disabled. F=Enabled. |
FWC |
Force |
T=Force F=Force |
EXC |
EXEC Syntax |
T=EXEC Syntax Enabled. F=EXEC Syntax Disabled. |
XSM |
Schema Field |
Default=Default. Database=Database Name. Owner=Owner Name. |
MDI |
Set Metadata ID Default |
T= F= |
DPM |
Disable |
T= F= |
BTD |
Bind |
T=Bind F=Bind |
NUM |
Numeric Settings |
NLS=Use Oracle NLS numeric settings (to determine the decimal and group separator). MS=Use Microsoft regional settings. US=Use US settings. |
ODA |
Use |
T= Use F= Do not use |
STE |
SQL Translate ORA Errors Specifies whether the Oracle Database ODBC driver is to translate the Oracle error codes |
T=Translate ORA errors. F=Do not translate any ORA error. By default, |
TSZ |
Token Size |
User-supplied numeric value. Sets the token size to the nearest multiple of 1 KB (1024 bytes) beginning at 4 KB (4096 bytes). The default size is 8 KB (8192 bytes). The maximum value that can be set is 128 KB (131068 bytes). |
If the following keyword is specified in the connection string, the Oracle Database ODBC driver does not read values defined from the Administrator:
DRIVER={Oracle ODBC Driver}
Examples of valid connection strings are:
1) DSN=Personnel;UID=Kotzwinkle;PWD=;2) DRIVER={Oracle ODBC Driver};UID=Kotzwinkle;PWD=whatever;DBQ=instl_alias;DBA=W;
See Also:
-
Connecting to an Oracle Data Source for all users
-
SQLDriverConnect Implementation for programmers
Parent topic: Oracle Database ODBC Driver for Programmers
5.2 SQLDriverConnect Implementation
The following table describes the keywords required by the
SQLDriverConnect
connection string.
Table 5-2 Keywords Required by the SQLDriverConnect Connection String
Keyword | Description |
---|---|
DSN |
The name of the data source. |
DBQ |
The TNS Service Name. See Creating Oracle Database ODBC Driver TNS Service Names. For more information, see the Oracle Net Services documentation. |
UID |
The user login ID or user name. |
PWD |
The user-specified password. |
Parent topic: Oracle Database ODBC Driver for Programmers
5.3 Reducing Lock Timeout in a Program
The Oracle server waits indefinitely for lock conflicts between transactions, to be
resolved. You can limit the amount of time that
the Oracle server waits for locks to be resolved
by calling the ODBC
SQLSetConnectAttr
function before
connecting to the data source.
Specify a non-zero value for the SQL_ATTR_QUERY_TIMEOUT
attribute in
the ODBC SQLSetStmtAttr
function.
If you specify a lock timeout value using the ODBC
SQLSetConnectAttr
function, it
overrides any value specified in the
oraodbc.ini
file.
See Also:
Reducing Lock Timeout for more
information about specifying a value in the
oraodbc.ini
file
Parent topic: Oracle Database ODBC Driver for Programmers
5.4 Linking with odbc32.lib (Windows) or libodbc.so (UNIX)
For Windows platforms, when you link your program, you must link it with the import
library odbc32.lib
.
For UNIX platforms, an ODBC application must be linked to libodbc.so
.
Parent topic: Oracle Database ODBC Driver for Programmers
5.5 Information about ROWID
The ODBC SQLSpecialColumns
function returns information about the
columns in a table. When used with the Oracle Database ODBC driver, it returns
information about the Oracle ROWID
s associated with an Oracle
table.
Parent topic: Oracle Database ODBC Driver for Programmers
5.6 ROWID in a WHERE Clause
ROWID
s can be used in the WHERE
clause of an SQL
statement. However, the ROWID
value must be presented in a parameter
marker.
Parent topic: Oracle Database ODBC Driver for Programmers
5.7 Enabling Result Sets
Oracle reference cursors (Result Sets) allow an application to retrieve data using stored procedures and stored functions. The following information identifies how to use reference cursors to enable Result Sets through ODBC.
-
The ODBC syntax for calling stored procedures must be used. Native PL/SQL is not supported through ODBC. The following identifies how to call the procedure or function without a package and within a package. The package name, in this case, is RSET.
Procedure call: {CALL Example1(?)} {CALL RSET.Example1(?)} Function Call: {? = CALL Example1(?)} {? = CALL RSET.Example1(?)}
-
The PL/SQL reference cursor parameters are omitted when calling the procedure. For example, assume that the procedure Example2 is defined to have four parameters. Parameters 1 and 3 are reference cursor parameters and parameters 2 and 4 are character strings. The call is specified as:
{CALL RSET.Example2("Literal 1", "Literal 2")}
The following example application shows how to return a Result Set using the Oracle Database ODBC driver:
/* * Sample Application using Oracle reference cursors via ODBC * * Assumptions: * * 1) Oracle Sample database is present with data loaded for the EMP table. * 2) Two fields are referenced from the EMP table ename and mgr. * 3) A data source has been setup to access the sample database. * * Program Description: * * Abstract: * * This program demonstrates how to return result sets using * Oracle stored procedures * * Details: * * This program: * Creates an ODBC connection to the database. * Creates a Packaged Procedure containing two result sets. * Executes the procedure and retrieves the data from both result sets. * Displays the data to the user. * Deletes the package then logs the user out of the database. * * * The following is the actual PL/SQL this code generates to * create the stored procedures. * * DROP PACKAGE ODBCRefCur; * * CREATE PACKAGE ODBCRefCur AS * TYPE ename_cur IS REF CURSOR; * TYPE mgr_cur IS REF CURSOR; * PROCEDURE EmpCurs(Ename IN OUT ename_cur, Mgr IN OUT mgr_cur, pjob IN VARCHAR2); * END; * * CREATE or REPLACE PACKAGE BODY ODBCRefCur AS * PROCEDURE EmpCurs(Ename IN OUT ename_cur, Mgr IN OUT mgr_cur, pjob IN VARCHAR2) * AS * BEGIN * IF NOT Ename%ISOPEN * THEN * OPEN Ename for SELECT ename from emp; * END IF; * IF NOT Mgr%ISOPEN * THEN * OPEN Mgr for SELECT mgr from emp where job = pjob; * END IF; * END; * END; * */ /* Include Files */ #ifdef WIN32 #include <windows.h> #endif #include <stdio.h> #include <sql.h> #include <sqlext.h> /* Defines */ #define JOB_LEN 9 #define DATA_LEN 100 #define SQL_STMT_LEN 500 /* Procedures */ void DisplayError(SWORD HandleType, SQLHANDLE hHandle, char *Module); /* Main Program */ int main() { SQLHENV hEnv; SQLHDBC hDbc; SQLHSTMT hStmt; SQLRETURN rc; char *DefUserName ="scott"; char *DefPassWord ="tiger"; SQLCHAR ServerName[DATA_LEN]; SQLCHAR *pServerName=ServerName; SQLCHAR UserName[DATA_LEN]; SQLCHAR *pUserName=UserName; SQLCHAR PassWord[DATA_LEN]; SQLCHAR *pPassWord=PassWord; char Data[DATA_LEN]; SQLINTEGER DataLen; char error[DATA_LEN]; char *charptr; SQLCHAR SqlStmt[SQL_STMT_LEN]; SQLCHAR *pSqlStmt=SqlStmt; char *pSalesMan = "SALESMAN"; SQLINTEGER sqlnts=SQL_NTS; /* Allocate the Environment Handle */ rc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv ); if (rc != SQL_SUCCESS) { printf( "Cannot Allocate Environment Handle/n"); printf( "/nHit Return to Exit/n"); charptr = gets ((char *)error); exit(1); } /* Set the ODBC Version */ rc = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0); if (rc != SQL_SUCCESS) { printf("Cannot Set ODBC Version/n"); printf("/nHit Return to Exit/n"); charptr = gets((char *)error); exit(1); } /* Allocate the Connection handle */ rc = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc); if (rc != SQL_SUCCESS) { printf("Cannot Allocate Connection Handle/n"); printf("/nHit Return to Exit/n"); charptr = gets((char*) error); exit(1); } /* Get User Information */ lstrcpy((char*) pUserName, DefUserName); lstrcpy((char*) pPassWord, DefPassWord); /* Data Source name */ printf( "/nEnter the ODBC Data Source Name/n" ); charptr = gets((char*) ServerName); /* User Name */ printf("/nEnter User Name Default [%s]/n", pUserName); charptr = gets((char*) UserName); if (*charptr == '/0') { lstrcpy((char*) pUserName, (char*) DefUserName); } /* Password */ printf ("/nEnter Password Default [%s]/n", pPassWord); charptr = gets((char*) PassWord); if (*charptr == '/0') { lstrcpy((char*) pPassWord, (char*) DefPassWord); } /* Connection to the database */ rc = SQLConnect(hDbc, pServerName, (SQLSMALLINT) lstrlen((char *)pServerName), pUserName, (SQLSMALLINT) lstrlen((char*)pUserName), pPassWord, (SQLSMALLINT) lstrlen((char *)pPassWord)); if (rc != SQL_SUCCESS) { DisplayError(SQL_HANDLE_DBC, hDbc, "SQLConnect"); } /* Allocate a Statement */ rc = SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt); if (rc != SQL_SUCCESS) { printf( "Cannot Allocate Statement Handle/n"); printf( "/nHit Return to Exit/n"); charptr = gets((char *)error); exit(1); } /* Drop the Package */ lstrcpy((char *) pSqlStmt, "DROP PACKAGE ODBCRefCur"); rc = SQLExecDirect(hStmt, pSqlStmt, lstrlen((char *)pSqlStmt)); /* Create the Package Header */ lstrcpy((char *) pSqlStmt, "CREATE PACKAGE ODBCRefCur AS/n" ); lstrcat((char *) pSqlStmt, " TYPE ename_cur IS REF CURSOR;/n" ); lstrcat((char *) pSqlStmt, " TYPE mgr_cur IS REF CURSOR;/n" ); lstrcat((char *) pSqlStmt, " PROCEDURE EmpCurs (Ename IN OUT ename_cur," ); lstrcat((char *) pSqlStmt, " Mgr IN OUT mgr_cur,pjob IN VARCHAR2);/n/n"); lstrcat((char *) pSqlStmt, "END;/n" ); rc = SQLExecDirect(hStmt, pSqlStmt, lstrlen((char *)pSqlStmt)); if (rc != SQL_SUCCESS) { DisplayError(SQL_HANDLE_STMT, hStmt, "SQLExecDirect"); } /* Create the Package Body */ lstrcpy((char *) pSqlStmt, "CREATE PACKAGE BODY ODBCRefCur AS/n" ); lstrcat((char *) pSqlStmt, " PROCEDURE EmpCurs (Ename IN OUT ename_cur," ); lstrcat((char *) pSqlStmt, " Mgr IN OUT mgr_cur, pjob IN VARCHAR2)/n" ); lstrcat((char *) pSqlStmt, " AS/n" ); lstrcat((char *) pSqlStmt, " BEGIN/n" ); lstrcat((char *) pSqlStmt, " IF NOT Ename%ISOPEN/n" ); lstrcat((char *) pSqlStmt, " THEN/n" ); lstrcat((char *) pSqlStmt, " OPEN Ename for SELECT ename from emp;/n" ); lstrcat((char *) pSqlStmt, " END IF;/n/n" ); lstrcat((char *) pSqlStmt, " IF NOT Mgr%ISOPEN/n THEN/n" ); lstrcat((char *) pSqlStmt, " OPEN Mgr for SELECT mgr from emp where job = pjob;/n"); lstrcat((char *) pSqlStmt, " END IF;/n" ); lstrcat((char *) pSqlStmt, " END;/n" ); lstrcat((char *) pSqlStmt, "END;/n" ); rc = SQLExecDirect(hStmt, pSqlStmt, lstrlen((char *)pSqlStmt)); if(rc != SQL_SUCCESS) DisplayError(SQL_HANDLE_STMT, hStmt, "SQLExecDirect"); /* Bind the Parameter */ rc = SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, JOB_LEN, 0, pSalesMan, 0, &sqlnts); /* Call the Store Procedure which executes the Result Sets */ lstrcpy( (char *) pSqlStmt, "{CALL ODBCRefCur.EmpCurs(?)}"); rc = SQLExecDirect(hStmt, pSqlStmt, lstrlen((char *)pSqlStmt)); if(rc != SQL_SUCCESS) DisplayError(SQL_HANDLE_STMT, hStmt, "SQLExecDirect"); /* Bind the Data */ rc = SQLBindCol(hStmt, 1, SQL_C_CHAR, Data, sizeof(Data), &DataLen); if(rc != SQL_SUCCESS) DisplayError(SQL_HANDLE_STMT, hStmt, "SQLBindCol"); /* Get the data for Result Set 1 */ printf("/nEmployee Names/n/n"); while(rc == SQL_SUCCESS) { rc = SQLFetch(hStmt); if(rc == SQL_SUCCESS) printf("%s/n", Data); else if(rc != SQL_NO_DATA) DisplayError(SQL_HANDLE_STMT, hStmt, "SQLFetch"); } printf( "/nFirst Result Set - Hit Return to Continue/n"); charptr = gets ((char *)error); /* Get the Next Result Set */ rc = SQLMoreResults( hStmt ); if(rc != SQL_SUCCESS) DisplayError(SQL_HANDLE_STMT, hStmt, "SQLMoreResults"); /* Get the data for Result Set 2 */ printf("/nManagers/n/n"); while (rc == SQL_SUCCESS) { rc = SQLFetch(hStmt); if(rc == SQL_SUCCESS) printf("%s/n", Data); else if (rc != SQL_NO_DATA) DisplayError(SQL_HANDLE_STMT, hStmt, "SQLFetch"); } printf("/nSecond Result Set - Hit Return to Continue/n"); charptr = gets((char *)error); /* Should Be No More Results Sets */ rc = SQLMoreResults( hStmt ); if (rc != SQL_NO_DATA) DisplayError(SQL_HANDLE_STMT, hStmt, "SQLMoreResults"); /* Drop the Package */ lstrcpy((char *)pSqlStmt, "DROP PACKAGE ODBCRefCur"); rc = SQLExecDirect(hStmt, pSqlStmt, lstrlen((char *)pSqlStmt)); /* Free handles close connections to the database */ SQLFreeHandle( SQL_HANDLE_STMT, hStmt ); SQLDisconnect( hDbc ); SQLFreeHandle( SQL_HANDLE_DBC, hDbc ); SQLFreeHandle( SQL_HANDLE_ENV, hEnv ); printf( "/nAll Done - Hit Return to Exit/n"); charptr = gets ((char *)error); return(0); } /* Display Error Messages */ void DisplayError( SWORD HandleType, SQLHANDLE hHandle, char *Module ) { SQLCHAR MessageText[255]; SQLCHAR SQLState[80]; SQLRETURN rc=SQL_SUCCESS; LONG NativeError; SWORD RetLen; SQLCHAR error[25]; char *charptr; rc = SQLGetDiagRec(HandleType, hHandle, 1, SQLState, &NativeError, MessageText, 255, &RetLen); printf( "Failure Calling %s/n", Module ); if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { printf( "/t/t/t State: %s/n", SQLState); printf( "/t/t/t Native Error: %d/n", NativeError ); printf( "/t/t/t Error Message: %s/n", MessageText ); } printf( "/nHit Return to Exit/n"); charptr = gets ((char *)error); exit(1); }
Parent topic: Oracle Database ODBC Driver for Programmers
5.8 Enabling EXEC Syntax
If the syntax of your SQL Server EXEC
statement can be readily
translated to an equivalent Oracle procedure call without change, the Oracle
Database ODBC driver can translate it, if you enable this option.
The complete name of a SQL Server procedure consists of up to four identifiers:
-
server name
-
database name
-
owner name
-
procedure name
The format for the name is:
[[[server.][database].][owner_name].]procedure_name
During the migration of the SQL Server database to Oracle, the definition of each SQL Server procedure (or function) is converted to its equivalent Oracle syntax and is defined in a schema in Oracle. Migrated procedures are often reorganized (and created in schemas) in one of these ways:
-
All procedures are migrated to one schema (the default option).
-
All procedures defined in one SQL Server database are migrated to the schema named with that database name.
-
All procedures owned by one user are migrated to the schema named with that user's name.
To support these three ways of organizing migrated procedures, you can specify one of these schema name options for translating procedure names. Object names in the translated Oracle procedure call are not case-sensitive.
Parent topic: Oracle Database ODBC Driver for Programmers
5.9 Enabling Event Notification for Connection Failures in an Oracle RAC Environment
If the SQL_ORCLATTR_FAILOVER_CALLBACK
and
SQL_ORCLATTR_FAILOVER_HANDLE
attributes of the
SQLSetConnectAttr
function are set when a connection failure occurs in an
Oracle Real Application Clusters (Oracle RAC) Database environment, event notification is
enabled. Both attributes are set using the SQLSetConnectAttr
function. The
symbols for the new attributes are defined in the file sqora.h
.
The SQL_ORCLATTR_FAILOVER_CALLBACK
attribute specifies the address of a routine to call when a failure event takes place.
The SQL_ORCLATTR_FAILOVER_HANDLE
attribute specifies a context handle that is passed as a parameter in the callback routine. This attribute is necessary for the ODBC application to determine which connection the failure event is taking place on.
The function prototype for the callback routine is:
void failover_callback(void *handle, SQLINTEGER fo_code)
The 'handle' parameter is the value that was set by the SQL_ORCLATTR_FAILOVER_HANDLE
attribute. Null is returned if the attribute has not been set.
The fo_code
parameter identifies the failure event that is taking
place. The failure events map directly to the events defined in the OCI programming
interface. The list of possible events is:
-
ODBC_FO_BEGIN
-
ODBC_FO_ERROR
-
ODBC_FO_ABORT
-
ODBC_FO_REAUTH
-
ODBC_FO_END
The following is a sample program that demonstrates, using this feature:
/* NAME ODBCCallbackTest DESCRIPTION Simple program to demonstrate the connection failover callback feature. PUBLIC FUNCTION(S) main PRIVATE FUNCTION(S) NOTES Command Line: ODBCCallbackTest filename [odbc-driver] */ #include <windows.h> #include <tchar.h> #include <malloc.h> #include <stdio.h> #include <string.h> #include <sql.h> #include <sqlext.h> #include "sqora.h" /* ** Function Prototypes */ void display_errors(SQLSMALLINT HandleType, SQLHANDLE Handle); void failover_callback(void *Handle, SQLINTEGER fo_code); /* ** Macros */ #define ODBC_STS_CHECK(sts) \ if (sts != SQL_SUCCESS) \ { \ display_errors(SQL_HANDLE_ENV, hEnv); \ display_errors(SQL_HANDLE_DBC, hDbc); \ display_errors(SQL_HANDLE_STMT, hStmt); \ return FALSE; \ } /* ** ODBC Handles */ SQLHENV *hEnv = NULL; // ODBC Environment Handle SQLHANDLE *hDbc = NULL; // ODBC Connection Handle SQLHANDLE *hStmt = NULL; // ODBC Statement Handle /* ** Connection Information */ TCHAR *dsn = _T("odbctest"); TCHAR *uid = _T("scott"); TCHAR *pwd = _T("tiger"); TCHAR *szSelect = _T("select * from emp"); /* ** MAIN Routine */ main(int argc, char **argv) { SQLRETURN rc; /* ** Allocate handles */ rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, (SQLHANDLE *)&hEnv); ODBC_STS_CHECK(rc) rc = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0); ODBC_STS_CHECK(rc); rc = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, (SQLHANDLE *)&hDbc); ODBC_STS_CHECK(rc); /* ** Connect to the database */ rc = SQLConnect(hDbc, dsn, (SQLSMALLINT)_tcslen(dsn), uid, (SQLSMALLINT)_tcslen(uid), pwd, (SQLSMALLINT)_tcslen(pwd)); ODBC_STS_CHECK(rc); /* ** Set the connection failover attributes */ rc = SQLSetConnectAttr(hDbc, SQL_ORCLATTR_FAILOVER_CALLBACK, &failover_callback, 0); ODBC_STS_CHECK(rc); rc = SQLSetConnectAttr(hDbc, SQL_ORCLATTR_FAILOVER_HANDLE, hDbc, 0); ODBC_STS_CHECK(rc); /* ** Allocate the statement handle */ rc = SQLAllocHandle(SQL_HANDLE_STMT, hDbc, (SQLHANDLE *)&hStmt); ODBC_STS_CHECK(rc); /* ** Wait for connection failovers */ while (TRUE) { Sleep(5000); rc = SQLExecDirect(hStmt,szSelect, _tcslen(szSelect)); ODBC_STS_CHECK(rc); rc = SQLFreeStmt(hStmt, SQL_CLOSE); ODBC_STS_CHECK(rc); } /* ** Free up the handles and close the connection */ rc = SQLFreeHandle(SQL_HANDLE_STMT, hStmt); ODBC_STS_CHECK(rc); rc = SQLDisconnect(hDbc); ODBC_STS_CHECK(rc); rc = SQLFreeHandle(SQL_HANDLE_DBC, hDbc); ODBC_STS_CHECK(rc); rc = SQLFreeHandle(SQL_HANDLE_ENV, hEnv); ODBC_STS_CHECK(rc); return TRUE; } /* ** Failover Callback Routine */ void failover_callback(void *Handle, SQLINTEGER fo_code) { switch(fo_code) { case ODBC_FO_BEGIN: printf("ODBC_FO_BEGIN recevied\n"); break; case ODBC_FO_ERROR: printf("ODBC_FO_ERROR recevied\n"); break; case ODBC_FO_ABORT: printf("ODBC_FO_ABORT recevied\n"); break; case ODBC_FO_REAUTH: printf("ODBC_FO_REAUTH recevied\n"); break; case ODBC_FO_END: printf("ODBC_FO_END recevied\n"); break; default: printf("Invalid or unknown ODBC failover code recevied\n"); break; } return; } /* ** Retrieve the errors associated with the handle passed ** and display them. */ void display_errors(SQLSMALLINT HandleType, SQLHANDLE Handle) { SQLTCHAR MessageText[256]; SQLTCHAR SqlState[5+1]; SQLSMALLINT i=1; SQLINTEGER NativeError; SQLSMALLINT TextLength; SQLRETURN sts = SQL_SUCCESS; if (Handle == NULL) return; /* Make sure all SQLState text is null terminated */ SqlState[5] = '\0'; /* ** Fetch and display all diagnostic records that exist for this handle */ while (sts == SQL_SUCCESS) { NativeError = 0; TextLength = 0; sts = SQLGetDiagRec(HandleType, Handle, i, SqlState, &NativeError, (SQLTCHAR *)&MessageText, sizeof(MessageText), &TextLength); if (sts == SQL_SUCCESS) { printf("[%s]%s\n", SqlState, MessageText); if (NativeError != 0) printf("Native Error Code: %d\n", NativeError); i++; } } return; }
Parent topic: Oracle Database ODBC Driver for Programmers
5.10 Using Implicit Results Feature through ODBC
Use this option when you migrate any third party ODBC application to Oracle Database
and you want to use implicit results functionality as supported by the previous vendor.
The Oracle Database ODBC driver supports implicit results with stored procedures or an
anonymous PL/SQL block. For the current release, implicit results are returned only for
SELECT
statements.
The following code example shows an example ODBC test case using an anonymous SQL script for implicit results.
const char *query1="declare \ c1 sys_refcursor; \ c2 sys_refcursor; \ begin \ open c1 for select empno,ename from emp where rownum<=3; \ dbms_sql.return_result(c1); \ open c2 for select empno,ename from emp where rownum<=3; \ dbms_sql.return_result(c2); end; "; int main( ) { ... ... //Allocate all required handles and establish a connection to the database. //Prepare and execute the above anonymous PL/SQL block SQLPrepare (hstmt, (SQLCHAR *) query1, SQL_NTS); SQLExecute(hstmt); //Bind the columns for the results from the first SELECT statement in an anonymous block. SQLBindCol (hstmt, 1, SQL_C_ULONG, &eno, 0, &jind); SQLBindCol (hstmt, 2, SQL_C_CHAR, empname, sizeof (empname),&enind); //Fetch implicit results through the SQLFetch( ) call. while((retCode = SQLFetch(hstmt)) != SQL_NO_DATA) { //Do whatever you want to do with the data. } retCode = SQLMoreResults(hstmt); if(retCode == SQL_SUCCESS) { printf("SQLMoreResults returned with SQL_SUCCESS\n"); //Bind the columns for the results from the second SELECT statement in an anonymous block. SQLBindCol (hstmt, 1, SQL_C_ULONG, &eno, 0, &jind); SQLBindCol (hstmt, 2, SQL_C_CHAR, empname, sizeof (empname),&enind); //Fetch implicit results through the SQLFetch( ) call. while((retCode = SQLFetch(hstmt)) != SQL_NO_DATA) { //Do whatever you want to do with data. } } }
Parent topic: Oracle Database ODBC Driver for Programmers
5.11 About Supporting Oracle TIMESTAMP WITH TIME ZONE and TIMESTAMP WITH LOCAL TIME ZONE Column Type in ODBC
The time zone is dictated by the system variable ORA_SDTZ
. The
system variable can be set to 'OS_TZ'
, 'DB_TZ'
, or a valid time
zone value. When ORA_SDTZ
is set to 'OS_TZ'
, the operating
system time zone is used. If it is set to 'DB_TZ'
, the default time zone set in
the database is used.
By default, when ORA_SDTZ
is not set, the operating system time zone
is used.
Note:
When setting the ORA_SDTZ
variable in a Microsoft Windows environment -- in the Registry, among system environment variables, or in a command prompt window -- do not enclose the time zone value in quotes.
See Also:
Oracle Database Globalization Support Guide for information about Datetime data types and time zone support
Fetching Data from These Time Zone Columns Using the Variable of ODBC Data Type TIMESTAMP_STRUCT
The following example demonstrates how to fetch data from TIMESTAMP WITH TIME ZONE
and TIMESTAMP WITH LOCAL TIME ZONE
column using the variable of ODBC datatype TIMESTAMP_STRUCT
.
Example 5-1 How to Fetch Data from TIMESTAMP WITH TIME ZONE and TIMESTAMP WITH LOCAL TIME ZONE Columns Using the Variable of ODBC Data Type TIMESTAMP_STRUCT
int main()
{
...
...
/* TSTAB table's DDL statement:
* ---------------------------
* CREATE TABLE TSTAB (COL_TSTZ TIMESTAMP WITH TIME ZONE,
* COL_TSLTZ TIMESTAMP WITH LOCAL TIME ZONE);
*
* Insert statement:
* ----------------
* Sample #1:
* ---------
* INSERT INTO TSTAB VALUES (TIMESTAMP '2010-03-13 03:47:30.123456 America/Los_Angeles'
* TIMESTAMP '2010-04-14 04:47:30.123456 America/Los_Angeles');
*
* Sample #2:
* ---------
* INSERT INTO TSTAB VALUES ('22-NOV-1963 12:30:00.000000 PM',
* '24-NOV-1974 02:30:00.000000 PM');
*
* Refer Oracle Database documentations to know more details about TIMESTAMP
* WITH TIME ZONE and TIMESTAMP WITH LOCAL TIME ZONE columns.
*/
SQLCHAR sqlSelQuery[] = "SELECT COL_TSTZ, COL_TSLTZ FROM TSTAB";
TIMESTAMP_STRUCT timestampcol1;
TIMESTAMP_STRUCT timestampcol2;
...
...
/* Allocate the ODBC statement handle. */
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
/* Execute the statement sqlSelQuery. */
SQLExecDirect(hstmt, sqlSelQuery, SQL_NTS);
/* Bind the variable to read the value from the TIMESTAMP WITH TIME ZONE column. */
SQLBindCol(hstmt, 1, SQL_C_TIMESTAMP, ×tampcol1, sizeof(timestampcol1), NULL);
/* Bind the variable to read the value from the TIMESTAMP WITH LOCAL TIME ZONE column. */
SQLBindCol(hstmt, 2, SQL_C_TIMESTAMP, ×tampcol2, sizeof(timestampcol2), NULL);
...
...
/* Fetch data from the TSTAB table. */
retcode = SQLFetch(hstmt);
/* Values of column COL_TSTZ and COL_TSLTZ are available in variables
* timestampcol1 and timestampcol2 respectively. Refer to Microsoft ODBC
* documentation for more information about data type TIMESTAMP_STRUCT. */
...
...
/* Close the statement. */
SQLFreeStmt(hstmt, SQL_CLOSE);
/* Free the statement handle. */
SQLFreeHandle(SQL_HANDLE_STMT, hstmt); ... ... }
Example 5-2 How to Insert Data into TIMESTAMP WITH TIME ZONE and TIMESTAMP WITH LOCAL TIME ZONE Columns
int main()
{
...
...
SQLCHAR sqlInsQuery[] = "INSERT INTO TSTAB VALUES (?, ?)";
TIMESTAMP_STRUCT timestampcol1;
TIMESTAMP_STRUCT timestampcol2;
...
...
/* Input the value for column COL_TSTZ in table TSTAB. */
timestampcol1.year = 2000;
timestampcol1.month = 1;
timestampcol1.day = 1;
timestampcol1.hour = 0;
timestampcol1.minute = 0;
timestampcol1.second = 1;
timestampcol1.fraction = 1000;
/* Input the value for column COL_TSLTZ in table TSTAB. */
timestampcol1.year = 2012;
timestampcol1.month = 2;
timestampcol1.day = 5;
timestampcol1.hour = 10;
timestampcol1.minute = 30;
timestampcol1.second = 10;
timestampcol1.fraction = 1000;
...
...
/* Allocate the ODBC statement handle. */
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
...
...
/* Bind the input value for column COL_TSTZ. */
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_TIMESTAMP, SQL_TIMESTAMP,
0, 0, ×tampcol1, sizeof(timestampcol1), NULL);
/* Bind the input value for column COL_TSLTZ. */
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_TIMESTAMP, SQL_TIMESTAMP,
0, 0, ×tampcol2, sizeof(timestampcol2), NULL);
...
...
/* Execute the statement sqlInsQuery. */
SQLExecDirect(hstmt, sqlInsQuery, SQL_NTS);
/* Close the statement. */
SQLFreeStmt(hstmt, SQL_CLOSE);
/* Free the statement handle. */
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
...
...
}
Parent topic: Oracle Database ODBC Driver for Programmers
5.12 About the Effect of Setting ORA_SDTZ in Oracle Clients (OCI, SQL*Plus, Oracle Database ODBC Driver, and Others)
Describes the effect of setting the system variable ORA_SDTZ
in Oracle Clients.
The time zone is dictated by the system variable ORA_SDTZ
.
The following sections describe the effects of not setting and setting the system
variable ORA_SDTZ
in Oracle Clients (OCI, SQL*Plus, Oracle Database
ODBC Driver, and others). The examples in these sections are run in India (GMT+5:30)
time zone.
See Also:
Oracle Database Globalization Support Guide for more information about setting the session time zone
Environment Setup
To set up the environment, create the following table with TSLTZ
(TIMESTAMP WITH LOCAL TIME ZONE) column and insert the value of 01/01/2016 00:00
GMT into the TSLTZ
column as follows:
Example 5-3 How to Set Up the Environment
The following example sets up the environment for the example sections that follow.
SQL> create table timezone_demo(col1 TIMESTAMP WITH LOCAL TIME ZONE);
Table created.
SQL> INSERT INTO TIMEZONE_DEMO VALUES(TIMESTAMP '2016-01-01 00:00:00.000000 ETC/GREENWICH');
1 row created.
When ORA_SDTZ Is Not Set in the Environment
When ORA_SDTZ
is not set in the environment, then the operating system (OS) time zone setting is taken as the default time zone for Oracle Clients. For example:
Example 5-4 What Happens When ORA_SDTZ Is Not Set
C:\Users\example.ORADEV>set ORA_SDTZ=
C:\Users\example.ORADEV>sqlplus scott/password@//host01.example.com:1521/ORCL12C1
SQL*Plus: Release 23.0.0.0.0 - Production on Wed Jun 19 13:14:27 2024 Version 23.4.1.24.05
Copyright (c) 1982, 2024, Oracle. All rights reserved.
Connected to:Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - Development Version 23.4.0.24.00
With the Partitioning, OLAP, Advanced Analytics, and Real Application Testing options
SQL> select sessiontimezone from dual;
SESSIONTIMEZONE
---------------------------------------------------------------------------
+05:30
SQL> select * from timezone_demo;
COL1
---------------------------------------------------------------------------
01-JAN-24 05.30.00.000000 AM
Setting ORA_SDTZ to the Operating System (OS) Timezone in the Environment
When ORA_SDTZ
is set to the operating system (OS) Time zone, the Oracle Client’s user session is set to the OS time zone setting. You can either unset it in the environment or set ORA_SDTZ
to OS_TZ
. For example:
Example 5-5 What Happens When ORA_SDTZ Is Set to the Operating System (OS) Timezone
C:\Users\example.ORADEV>set ORA_SDTZ=OS_TZ
C:\Users\example.ORADEV>sqlplus scott/password@//host01.example.com:1521/ORCL12C1
SQL*Plus: Release 23.0.0.0.0 - for Oracle Cloud on Wed Jun 19 13:14:27 2024 Version 23.4.1.24.06
Copyright (c) 1982, 2024, Oracle. All rights reserved.
Connected to:Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - for Oracle Cloud Version 23.4.1.24.06
With the Partitioning, OLAP, Advanced Analytics, and Real Application Testing options
SQL> select sessiontimezone from dual;
SESSIONTIMEZONE
---------------------------------------------------------------------------
+05:30
SQL> select * from timezone_demo;
COL1
---------------------------------------------------------------------------
01-JAN-24 05.30.00.000000 AM
Setting ORA_SDTZ to a Specific Time Zone in the Environment
The Oracle Client can be set to retrieve the time stamp value adjusted to a specific
time zone (for example, Helsinki Time Zone). To do this, you can set
ORA_SDTZ
to the Oracle Time Zone region name for the
corresponding time zone (Oracle Time Zone Region Name for Helsinki Time Zone is
Europe/Helsinki
). For example:
Example 5-6 What Happens When ORA_SDTZ Is Set to a Specific Time Zone
C:\Users\example.ORADEV>set ORA_SDTZ=Europe/Helsinki
C:\Users\example.ORADEV>sqlplus scott/password@//host01.example.com:1521/ORCL12C1
SQL*Plus: Release 23.0.0.0.0 - for Oracle Cloud on Wed Jun 19 13:14:27 2024 Version 23.4.1.24.06
Copyright (c) 1982, 2024, Oracle. All rights reserved.
Connected to:Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - for Oracle Cloud Version 23.4.1.24.06
With the Partitioning, OLAP, Advanced Analytics, and Real Application Testing options
SQL> select sessiontimezone from dual;
SESSIONTIMEZONE
---------------------------------------------------------------------------
Europe/Helsinki
SQL> select * from timezone_demo;
COL1
---------------------------------------------------------------------------
01-JAN-24 02.00.00.000000 AM
Parent topic: Oracle Database ODBC Driver for Programmers