/* * iodbctest.c * * $Id$ * * Sample ODBC program * * The iODBC driver manager. * * Copyright (C) 1996-2021 OpenLink Software * All Rights Reserved. * * This software is released under the terms of either of the following * licenses: * * - GNU Library General Public License (see LICENSE.LGPL) * - The BSD License (see LICENSE.BSD). * * Note that the only valid version of the LGPL license as far as this * project is concerned is the original GNU Library General Public License * Version 2, dated June 1991. * * While not mandated by the BSD license, any patches you make to the * iODBC source code may be contributed back into the iODBC project * at your discretion. Contributions will benefit the Open Source and * Data Access community as a whole. Submissions may be made at: * * http://www.iodbc.org * * * GNU Library Generic Public License Version 2 * ============================================ * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; only * Version 2 of the License dated June 1991. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * * The BSD License * =============== * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name of OpenLink Software Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include /* * Prototypes */ int ODBC_Connect (char *connStr); int ODBC_Disconnect (void); int ODBC_Errors (char *where); int ODBC_Test (void); #define MAXCOLS 32 #ifdef UNICODE #define TEXT(x) (SQLWCHAR *) L##x #define TEXTC(x) (SQLWCHAR) L##x #define TXTLEN(x) wcslen((wchar_t *) x) #define TXTCMP(x1,x2) wcscmp((wchar_t *) x1, (wchar_t *) x2) # ifdef WIN32 #define OPL_A2W(a, w, cb) \ MultiByteToWideChar(CP_ACP, 0, a, -1, w, cb) # else #define OPL_A2W(XA, XW, SIZE) mbstowcs(XW, XA, SIZE) # endif /* WIN32 */ #else #define TEXT(x) (SQLCHAR *) x #define TEXTC(x) (SQLCHAR) x #define TXTLEN(x) strlen((char *) x) #define TXTCMP(x1,x2) strcmp((char *) x1, (char *) x2) #endif /* UNICODE */ #define NUMTCHAR(X) (sizeof (X) / sizeof (SQLTCHAR)) /* * Global variables */ HENV henv = SQL_NULL_HANDLE; HDBC hdbc = SQL_NULL_HANDLE; HSTMT hstmt = SQL_NULL_HANDLE; int connected = 0; /* * Unicode conversion routines */ #ifdef UNICODE static SQLWCHAR * strcpy_A2W (SQLWCHAR * destStr, char *sourStr) { size_t length; if (!sourStr || !destStr) return destStr; length = strlen (sourStr); if (length > 0) OPL_A2W (sourStr, destStr, length); destStr[length] = L'\0'; return destStr; } #endif /* * Connect to the datasource * * The connect string can have the following parts and they refer to * the values in the odbc.ini file * * DSN= [mandatory] * HOST= [optional - value of Host] * SVT= [optional - value of ServerType] * DATABASE= [optional - value of Database] * OPTIONS= [optional - value of Options] * UID= [optional - value of LastUser] * PWD= [optional] * READONLY= [optional - value of ReadOnly] * FBS= [optional - value of FetchBufferSize] * * Examples: * * HOST=star;SVT=SQLServer 2000;UID=demo;PWD=demo;DATABASE=pubs * * DSN=pubs_sqlserver;PWD=demo */ SQLTCHAR outdsn[4096]; /* Store completed DSN for later use */ int ODBC_Connect (char *connStr) { short buflen; SQLCHAR dataSource[1024]; SQLTCHAR dsn[33]; SQLTCHAR desc[255]; SQLTCHAR driverInfo[255]; SQLSMALLINT len1, len2; int status; #ifdef UNICODE SQLWCHAR wdataSource[1024]; #endif #if (ODBCVER < 0x0300) if (SQLAllocEnv (&henv) != SQL_SUCCESS) return -1; # ifdef UNICODE SQLSetEnvAttr (henv, SQL_ATTR_APP_UNICODE_TYPE, (SQLPOINTER) SQL_DM_CP_DEF, SQL_IS_UINTEGER); #endif if (SQLAllocConnect (henv, &hdbc) != SQL_SUCCESS) return -1; #else if (SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv) != SQL_SUCCESS) return -1; SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER); # ifdef UNICODE SQLSetEnvAttr (henv, SQL_ATTR_APP_UNICODE_TYPE, (SQLPOINTER) SQL_DM_CP_DEF, SQL_IS_UINTEGER); #endif if (SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc) != SQL_SUCCESS) return -1; #endif /* * Set the application name */ SQLSetConnectOption (hdbc, SQL_APPLICATION_NAME, (SQLULEN) TEXT ("odbctest")); /* * Show the version number of the driver manager */ status = SQLGetInfo (hdbc, SQL_DM_VER, driverInfo, sizeof (driverInfo), &len1); if (status == SQL_SUCCESS) { #ifdef UNICODE printf ("Driver Manager: %S\n", driverInfo); #else printf ("Driver Manager: %s\n", driverInfo); #endif } /* * Either use the connect string provided on the command line or * ask for one. If an empty string or a ? is given, show a nice * list of options */ if (connStr && *connStr) strcpy ((char *) dataSource, connStr); else while (1) { /* * Ask for the connect string */ printf ("\nEnter ODBC connect string (? shows list): "); if (fgets ((char *) dataSource, sizeof (dataSource), stdin) == NULL) return 1; /* * Remove trailing '\n' */ dataSource[strlen ((char *) dataSource) - 1] = '\0'; /* * Check if the user wants to quit */ if (!strcmp ((char *)dataSource, "quit") || !strcmp ((char *)dataSource, "exit")) return -1; /* * If the user entered something other than a ? * break out of the while loop */ if (*dataSource && *dataSource != '?') break; /* * Print headers */ fprintf (stderr, "\n%-32s | %-40s\n", "DSN", "Driver"); fprintf (stderr, "------------------------------------------------------------------------------\n"); /* * Goto the first record */ if (SQLDataSources (henv, SQL_FETCH_FIRST, dsn, NUMTCHAR (dsn), &len1, desc, NUMTCHAR (desc), &len2) != SQL_SUCCESS) continue; /* * Show all records */ do { #ifdef UNICODE fprintf (stderr, "%-32S | %-40S\n", dsn, desc); #else fprintf (stderr, "%-32s | %-40s\n", dsn, desc); #endif } while (SQLDataSources (henv, SQL_FETCH_NEXT, dsn, NUMTCHAR (dsn), &len1, desc, NUMTCHAR (desc), &len2) == SQL_SUCCESS); } #ifdef UNICODE strcpy_A2W (wdataSource, (char *) dataSource); status = SQLDriverConnectW (hdbc, 0, (SQLWCHAR *) wdataSource, SQL_NTS, (SQLWCHAR *) outdsn, NUMTCHAR (outdsn), &buflen, SQL_DRIVER_COMPLETE); if (status != SQL_SUCCESS) ODBC_Errors ("SQLDriverConnectW"); #else status = SQLDriverConnect (hdbc, 0, (SQLCHAR *) dataSource, SQL_NTS, (SQLCHAR *) outdsn, NUMTCHAR (outdsn), &buflen, SQL_DRIVER_COMPLETE); if (status != SQL_SUCCESS) ODBC_Errors ("SQLDriverConnect"); #endif if (status != SQL_SUCCESS && status != SQL_SUCCESS_WITH_INFO) return -1; connected = 1; /* * Print out the version number and the name of the connected driver */ status = SQLGetInfo (hdbc, SQL_DRIVER_VER, driverInfo, NUMTCHAR (driverInfo), &len1); if (status == SQL_SUCCESS) { #ifdef UNICODE printf ("Driver: %S", driverInfo); #else printf ("Driver: %s", driverInfo); #endif status = SQLGetInfo (hdbc, SQL_DRIVER_NAME, driverInfo, NUMTCHAR (driverInfo), &len1); if (status == SQL_SUCCESS) { #ifdef UNICODE printf (" (%S)", driverInfo); #else printf (" (%s)", driverInfo); #endif } printf ("\n"); } /* * Show the list of supported functions in trace log */ #if (ODBCVER < 0x0300) { SQLUSMALLINT exists[100]; SQLGetFunctions (hdbc, SQL_API_ALL_FUNCTIONS, exists); } #else { SQLUSMALLINT exists[SQL_API_ODBC3_ALL_FUNCTIONS_SIZE]; SQLGetFunctions (hdbc, SQL_API_ODBC3_ALL_FUNCTIONS, exists); } #endif /* * Allocate statement handle */ #if (ODBCVER < 0x0300) if (SQLAllocStmt (hdbc, &hstmt) != SQL_SUCCESS) return -1; #else if (SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt) != SQL_SUCCESS) return -1; #endif return 0; } /* * Disconnect from the database */ int ODBC_Disconnect (void) { #if (ODBCVER < 0x0300) if (hstmt) SQLFreeStmt (hstmt, SQL_DROP); if (connected) SQLDisconnect (hdbc); if (hdbc) SQLFreeConnect (hdbc); if (henv) SQLFreeEnv (henv); #else if (hstmt) { SQLCloseCursor (hstmt); SQLFreeHandle (SQL_HANDLE_STMT, hstmt); } if (connected) SQLDisconnect (hdbc); if (hdbc) SQLFreeHandle (SQL_HANDLE_DBC, hdbc); if (henv) SQLFreeHandle (SQL_HANDLE_ENV, henv); #endif return 0; } /* * Perform a disconnect/reconnect using the DSN stored from the original * SQLDriverConnect */ int ODBC_Reconnect (void) { SQLRETURN status; SQLTCHAR buf[4096]; SQLSMALLINT len; /* * Free old statement handle */ #if (ODBCVER < 0x0300) SQLFreeStmt (hstmt, SQL_DROP); #else SQLFreeHandle (SQL_HANDLE_STMT, hstmt); #endif /* * Disconnect */ SQLDisconnect (hdbc); /* * Reconnect */ status = SQLDriverConnect (hdbc, 0, outdsn, SQL_NTS, buf, sizeof (buf), &len, SQL_DRIVER_NOPROMPT); /* * Allocate new statement handle */ if (SQL_SUCCEEDED (status)) { #if (ODBCVER < 0x0300) status = SQLAllocStmt (hdbc, &hstmt); #else status = SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt); #endif } /* * Show why we where unsuccessful and return an error */ if (!SQL_SUCCEEDED (status)) { ODBC_Errors ("DriverConnect (reconnect)"); return -1; } /* * Success */ return 0; } /* * Show all the error information that is available */ int ODBC_Errors (char *where) { SQLTCHAR buf[512]; SQLTCHAR sqlstate[15]; SQLINTEGER native_error = 0; int force_exit = 0; SQLRETURN sts; #if (ODBCVER < 0x0300) /* * Get statement errors */ while (hstmt) { sts = SQLError (henv, hdbc, hstmt, sqlstate, &native_error, buf, NUMTCHAR (buf), NULL); if (!SQL_SUCCEEDED (sts)) break; #ifdef UNICODE fprintf (stderr, "%s = %S (%ld) SQLSTATE=%S\n", where, buf, (long) native_error, sqlstate); #else fprintf (stderr, "%s = %s (%ld) SQLSTATE=%s\n", where, buf, (long) native_error, sqlstate); #endif /* * If the driver could not be loaded, there is no point in * continuing, after reading all the error messages */ if (!TXTCMP (sqlstate, TEXT ("IM003"))) force_exit = 1; } /* * Get connection errors */ while (hdbc) { sts = SQLError (henv, hdbc, SQL_NULL_HSTMT, sqlstate, &native_error, buf, NUMTCHAR (buf), NULL); if (!SQL_SUCCEEDED (sts)) break; #ifdef UNICODE fprintf (stderr, "%s = %S (%ld) SQLSTATE=%S\n", where, buf, (long) native_error, sqlstate); #else fprintf (stderr, "%s = %s (%ld) SQLSTATE=%s\n", where, buf, (long) native_error, sqlstate); #endif /* * If the driver could not be loaded, there is no point in * continuing, after reading all the error messages */ if (!TXTCMP (sqlstate, TEXT ("IM003"))) force_exit = 1; } /* * Get environment errors */ while (henv) { sts SQLError (henv, SQL_NULL_HDBC, SQL_NULL_HSTMT, sqlstate, &native_error, buf, NUMTCHAR (buf), NULL); if (!SQL_SUCCEEDED (sts)) break; #ifdef UNICODE fprintf (stderr, "%s = %S (%ld) SQLSTATE=%S\n", where, buf, (long) native_error, sqlstate); #else fprintf (stderr, "%s = %s (%ld) SQLSTATE=%s\n", where, buf, (long) native_error, sqlstate); #endif /* * If the driver could not be loaded, there is no point in * continuing, after reading all the error messages */ if (!TXTCMP (sqlstate, TEXT ("IM003"))) force_exit = 1; } #else /* ODBCVER */ int i; /* * Get statement errors */ i = 0; while (hstmt && i < 5) { sts = SQLGetDiagRec (SQL_HANDLE_STMT, hstmt, ++i, sqlstate, &native_error, buf, NUMTCHAR (buf), NULL); if (!SQL_SUCCEEDED (sts)) break; #ifdef UNICODE fprintf (stderr, "%d: %s = %S (%ld) SQLSTATE=%S\n", i, where, buf, (long) native_error, sqlstate); #else fprintf (stderr, "%d: %s = %s (%ld) SQLSTATE=%s\n", i, where, buf, (long) native_error, sqlstate); #endif /* * If the driver could not be loaded, there is no point in * continuing, after reading all the error messages */ if (!TXTCMP (sqlstate, TEXT ("IM003"))) force_exit = 1; } /* * Get connection errors */ i = 0; while (hdbc && i < 5) { sts = SQLGetDiagRec (SQL_HANDLE_DBC, hdbc, ++i, sqlstate, &native_error, buf, NUMTCHAR (buf), NULL); if (!SQL_SUCCEEDED (sts)) break; #ifdef UNICODE fprintf (stderr, "%d: %s = %S (%ld) SQLSTATE=%S\n", i, where, buf, (long) native_error, sqlstate); #else fprintf (stderr, "%d: %s = %s (%ld) SQLSTATE=%s\n", i, where, buf, (long) native_error, sqlstate); #endif /* * If the driver could not be loaded, there is no point in * continuing, after reading all the error messages */ if (!TXTCMP (sqlstate, TEXT ("IM003"))) force_exit = 1; } /* * Get environment errors */ i = 0; while (henv && i < 5) { sts = SQLGetDiagRec (SQL_HANDLE_ENV, henv, ++i, sqlstate, &native_error, buf, NUMTCHAR (buf), NULL); if (!SQL_SUCCEEDED (sts)) break; #ifdef UNICODE fprintf (stderr, "%d: %s = %S (%ld) SQLSTATE=%S\n", i, where, buf, (long) native_error, sqlstate); #else fprintf (stderr, "%d: %s = %s (%ld) SQLSTATE=%s\n", i, where, buf, (long) native_error, sqlstate); #endif /* * If the driver could not be loaded, there is no point in * continuing, after reading all the error messages */ if (!TXTCMP (sqlstate, TEXT ("IM003"))) force_exit = 1; } #endif /* ODBCVER */ /* * Force an exit status */ if (force_exit) exit (-1); return -1; } /* * Test program to run on the connected database */ int ODBC_Test () { SQLTCHAR request[4096]; SQLTCHAR fetchBuffer[1024]; char buf[4096]; int displayWidths[MAXCOLS]; int displayWidth; short numCols; short colNum; SQLTCHAR colName[50]; SQLSMALLINT colType; SQLULEN colPrecision; SQLLEN colIndicator; SQLSMALLINT colScale; SQLSMALLINT colNullable; unsigned long totalRows; unsigned long totalSets; int i; SQLRETURN sts; while (1) { /* * Ask the user for a dynamic SQL statement */ printf ("\nSQL>"); if (fgets (buf, sizeof (buf), stdin) == NULL) break; #ifndef UNICODE strcpy ((char *) request, (char *) buf); #else strcpy_A2W (request, buf); #endif request[TXTLEN (request) - 1] = TEXTC ('\0'); if (request[0] == TEXTC ('\0')) continue; /* * If the user just types tables, give him a list */ if (!TXTCMP (request, TEXT ("tables"))) { if (SQLTables (hstmt, NULL, 0, NULL, 0, NULL, 0, NULL, 0) != SQL_SUCCESS) { ODBC_Errors ("SQLTables(tables)"); continue; } } /* * If the user just types qualifiers, give him a list */ else if (!TXTCMP (request, TEXT ("qualifiers"))) { if (SQLTables (hstmt, TEXT ("%"), SQL_NTS, TEXT (""), 0, TEXT (""), 0, TEXT (""), 0) != SQL_SUCCESS) { ODBC_Errors ("SQLTables(qualifiers)"); continue; } } /* * If the user just types owners, give him a list */ else if (!TXTCMP (request, TEXT ("owners"))) { if (SQLTables (hstmt, TEXT (""), 0, TEXT ("%"), SQL_NTS, TEXT (""), 0, TEXT (""), 0) != SQL_SUCCESS) { ODBC_Errors ("SQLTables(owners)"); continue; } } /* * If the user just types "types", give him a list */ else if (!TXTCMP (request, TEXT ("types"))) { if (SQLTables (hstmt, TEXT (""), 0, TEXT (""), 0, TEXT (""), 0, TEXT ("%"), SQL_NTS) != SQL_SUCCESS) { ODBC_Errors ("SQLTables(types)"); continue; } } /* * If the user just types "datatypes", give him a list */ else if (!TXTCMP (request, TEXT ("datatypes"))) { if (SQLGetTypeInfo (hstmt, 0) != SQL_SUCCESS) { ODBC_Errors ("SQLGetTypeInfo"); continue; } } else if (!TXTCMP (request, TEXT ("reconnect"))) { if (ODBC_Reconnect()) return -1; continue; } #if defined (unix) else if (!TXTCMP (request, TEXT ("environment"))) { extern char **environ; for (i = 0; environ[i]; i++) fprintf (stderr, "%03d: [%s]\n", i, environ[i]); continue; } #endif else if (!TXTCMP (request, TEXT ("quit")) || !TXTCMP (request, TEXT ("exit"))) break; /* If you want to quit, just say so */ else { /* * Prepare & Execute the statement */ if (SQLPrepare (hstmt, (SQLTCHAR *) request, SQL_NTS) != SQL_SUCCESS) { ODBC_Errors ("SQLPrepare"); continue; } if ((sts = SQLExecute (hstmt)) != SQL_SUCCESS) { ODBC_Errors ("SQLExec"); if (sts != SQL_SUCCESS_WITH_INFO) continue; } } /* * Loop through all the result sets */ totalSets = 1; do { /* * Get the number of result columns for this cursor. * If it is 0, then the statement was probably a select */ if (SQLNumResultCols (hstmt, &numCols) != SQL_SUCCESS) { ODBC_Errors ("SQLNumResultCols"); goto endCursor; } if (numCols == 0) { SQLLEN nrows = 0; SQLRowCount (hstmt, &nrows); printf ("Statement executed. %ld rows affected.\n", nrows > 0 ? (long) nrows : 0L); goto endCursor; } if (numCols > MAXCOLS) { numCols = MAXCOLS; fprintf (stderr, "NOTE: Resultset truncated to %d columns.\n", MAXCOLS); } /* * Get the names for the columns */ putchar ('\n'); for (colNum = 1; colNum <= numCols; colNum++) { /* * Get the name and other type information */ if (SQLDescribeCol (hstmt, colNum, (SQLTCHAR *) colName, NUMTCHAR (colName), NULL, &colType, &colPrecision, &colScale, &colNullable) != SQL_SUCCESS) { ODBC_Errors ("SQLDescribeCol"); goto endCursor; } /* * Calculate the display width for the column */ switch (colType) { case SQL_VARCHAR: case SQL_CHAR: case SQL_WVARCHAR: case SQL_WCHAR: case SQL_GUID: displayWidth = colPrecision; break; case SQL_BINARY: displayWidth = colPrecision * 2; break; case SQL_LONGVARCHAR: case SQL_WLONGVARCHAR: case SQL_LONGVARBINARY: displayWidth = 30; /* show only first 30 */ break; case SQL_BIT: displayWidth = 1; break; case SQL_TINYINT: case SQL_SMALLINT: case SQL_INTEGER: case SQL_BIGINT: displayWidth = colPrecision + 1; /* sign */ break; case SQL_DOUBLE: case SQL_DECIMAL: case SQL_NUMERIC: case SQL_FLOAT: case SQL_REAL: displayWidth = colPrecision + 2; /* sign, comma */ break; #ifdef SQL_TYPE_DATE case SQL_TYPE_DATE: #endif case SQL_DATE: displayWidth = 10; break; #ifdef SQL_TYPE_TIME case SQL_TYPE_TIME: #endif case SQL_TIME: displayWidth = 8; break; #ifdef SQL_TYPE_TIMESTAMP case SQL_TYPE_TIMESTAMP: #endif case SQL_TIMESTAMP: displayWidth = 19; if (colScale > 0) displayWidth = displayWidth + colScale + 1; break; default: displayWidths[colNum - 1] = 0; /* skip other data types */ continue; } if (displayWidth < TXTLEN (colName)) displayWidth = TXTLEN (colName); if (displayWidth > NUMTCHAR (fetchBuffer) - 1) displayWidth = NUMTCHAR (fetchBuffer) - 1; displayWidths[colNum - 1] = displayWidth; /* * Print header field */ #ifdef UNICODE printf ("%-*.*S", displayWidth, displayWidth, colName); #else printf ("%-*.*s", displayWidth, displayWidth, colName); #endif if (colNum < numCols) putchar ('|'); } putchar ('\n'); /* * Print second line */ for (colNum = 1; colNum <= numCols; colNum++) { for (i = 0; i < displayWidths[colNum - 1]; i++) putchar ('-'); if (colNum < numCols) putchar ('+'); } putchar ('\n'); /* * Print all the fields */ totalRows = 0; while (1) { #if (ODBCVER < 0x0300) sts = SQLFetch (hstmt); #else sts = SQLFetchScroll (hstmt, SQL_FETCH_NEXT, 1); #endif if (sts == SQL_NO_DATA_FOUND) break; if (sts != SQL_SUCCESS) { ODBC_Errors ("Fetch"); break; } for (colNum = 1; colNum <= numCols; colNum++) { /* * Fetch this column as character */ #ifdef UNICODE sts = SQLGetData (hstmt, colNum, SQL_C_WCHAR, fetchBuffer, NUMTCHAR (fetchBuffer), &colIndicator); #else sts = SQLGetData (hstmt, colNum, SQL_C_CHAR, fetchBuffer, NUMTCHAR (fetchBuffer), &colIndicator); #endif if (sts != SQL_SUCCESS_WITH_INFO && sts != SQL_SUCCESS) { ODBC_Errors ("SQLGetData"); goto endCursor; } /* * Show NULL fields as **** */ if (colIndicator == SQL_NULL_DATA) { for (i = 0; i < displayWidths[colNum - 1]; i++) fetchBuffer[i] = TEXTC ('*'); fetchBuffer[i] = TEXTC ('\0'); } #ifdef UNICODE printf ("%-*.*S", displayWidths[colNum - 1], displayWidths[colNum - 1], fetchBuffer); #else printf ("%-*.*s", displayWidths[colNum - 1], displayWidths[colNum - 1], fetchBuffer); #endif if (colNum < numCols) putchar ('|'); } putchar ('\n'); totalRows++; } printf ("\n result set %lu returned %lu rows.\n\n", totalSets, totalRows); totalSets++; } while ((sts = SQLMoreResults (hstmt)) == SQL_SUCCESS); if (sts == SQL_ERROR) ODBC_Errors ("SQLMoreResults"); endCursor: #if (ODBCVER < 0x0300) SQLFreeStmt (hstmt, SQL_CLOSE); #else SQLCloseCursor (hstmt); #endif } return 0; } int main (int argc, char **argv) { /* * Set locale based on environment variables */ setlocale (LC_ALL, ""); /* * Show welcome message */ #ifdef UNICODE printf ("iODBC Unicode Demonstration program\n"); #else printf ("iODBC Demonstration program\n"); #endif printf ("This program shows an interactive SQL processor\n"); /* * Show a usage string when the user asks for this */ if (argc > 2 || (argc == 2 && argv[1][0] == '-')) { fprintf (stderr, "\nUsage:\n iodbctest [\"DSN=xxxx;UID=xxxx;PWD=xxxx\"]\n"); exit (0); } /* * If we can connect to this datasource, run the test program */ if (ODBC_Connect (argv[1]) != 0) { ODBC_Errors ("ODBC_Connect"); } else if (ODBC_Test () != 0) { ODBC_Errors ("ODBC_Test"); } /* * End the connection */ ODBC_Disconnect (); printf ("\nHave a nice day."); return 0; }