#include <stdio.h>
#include <string.h>
#if defined(__APPLE__) && !defined(NO_FRAMEWORKS)
#include <iODBC/sql.h>
#include <iODBC/sqlext.h>
#else
#include <sql.h>
#include <sqlext.h>
#endif
#define MAXCOLS 32
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
int connected;
int
ODBC_Connect (char *connStr)
{
short buflen;
char buf[257];
SQLCHAR dataSource[120];
SQLCHAR dsn[33];
SQLCHAR desc[255];
SQLCHAR driverInfo[255];
SWORD len1, len2;
int status;
#if (ODBCVER < 0x0300)
if (SQLAllocEnv (&henv) != SQL_SUCCESS)
return -1;
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);
if (SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc) != SQL_SUCCESS)
return -1;
#endif
if (connStr && *connStr)
strcpy ((char *) dataSource, connStr);
else
while (1)
{
printf ("\nEnter ODBC connect string (? shows list): ");
if (fgets ((char *) dataSource, sizeof (dataSource), stdin) == NULL)
return 1;
dataSource[strlen (dataSource) - 1] = '\0';
if (!strcmp (dataSource, "quit") || !strcmp (dataSource, "exit"))
return -1;
if (*dataSource && *dataSource != '?')
break;
fprintf (stderr, "\n%-30s | %-30s\n", "DSN", "Description");
fprintf (stderr, "---------------------------------------------------------------\n");
if (SQLDataSources (henv, SQL_FETCH_FIRST,
dsn, 33, &len1, desc, 255, &len2) != SQL_SUCCESS)
continue;
do
{
fprintf (stderr, "%-30s | %-30s\n", dsn, desc);
}
while (SQLDataSources (henv, SQL_FETCH_NEXT,
dsn, 33, &len1, desc, 255, &len2) == SQL_SUCCESS);
}
status = SQLDriverConnect (hdbc, 0, (UCHAR *) dataSource, SQL_NTS,
(UCHAR *) buf, sizeof (buf), &buflen, SQL_DRIVER_COMPLETE);
if (status != SQL_SUCCESS && status != SQL_SUCCESS_WITH_INFO)
return -1;
SQLSetConnectOption (hdbc, SQL_OPT_TRACEFILE, (UDWORD) "\\SQL.LOG");
connected = 1;
status = SQLGetInfo (hdbc, SQL_DRIVER_VER,
driverInfo, sizeof (driverInfo), &len1);
if (status == SQL_SUCCESS)
printf ("Driver: %s\n", driverInfo);
#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;
}
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)
{
int sts;
sts = SQLCloseCursor (hstmt);
if (sts != SQL_ERROR)
ODBC_Errors ("CloseCursor");
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;
}
void
ODBC_MesgHandler (char *reason)
{
fprintf (stderr, "ODBC_MesgHandler: %s\n", reason);
}
int
ODBC_Errors (char *where)
{
unsigned char buf[250];
unsigned char sqlstate[15];
while (SQLError (henv, hdbc, hstmt, sqlstate, NULL,
buf, sizeof(buf), NULL) == SQL_SUCCESS)
{
fprintf (stderr, "%s, SQLSTATE=%s\n", buf, sqlstate);
}
while (SQLError (henv, hdbc, SQL_NULL_HSTMT, sqlstate, NULL,
buf, sizeof(buf), NULL) == SQL_SUCCESS)
{
fprintf (stderr, "%s, SQLSTATE=%s\n", buf, sqlstate);
}
while (SQLError (henv, SQL_NULL_HDBC, SQL_NULL_HSTMT, sqlstate, NULL,
buf, sizeof(buf), NULL) == SQL_SUCCESS)
{
fprintf (stderr, "%s, SQLSTATE=%s\n", buf, sqlstate);
}
return -1;
}
int
ODBC_Test ()
{
char request[512];
char fetchBuffer[1000];
short displayWidths[MAXCOLS];
short displayWidth;
short numCols;
short colNum;
char colName[50];
short colType;
UDWORD colPrecision;
SDWORD colIndicator;
short colScale;
short colNullable;
UDWORD totalRows;
UDWORD totalSets;
int i;
while (1)
{
printf ("\nSQL> ");
if (fgets (request, sizeof (request), stdin) == NULL)
break;
request[strlen (request) - 1] = '\0';
if (request[0] == '\0')
continue;
if (!strcmp (request, "tables"))
{
if (SQLTables (hstmt, NULL, SQL_NTS, NULL, SQL_NTS, NULL, SQL_NTS,
NULL, SQL_NTS) != SQL_SUCCESS)
{
ODBC_Errors ("SQLTables");
continue;
}
}
else if (!strcmp (request, "quit") || !strcmp (request, "exit"))
break;
else
{
if (SQLPrepare (hstmt, (UCHAR *) request, SQL_NTS) != SQL_SUCCESS)
{
ODBC_Errors ("SQLPrepare");
continue;
}
if (SQLExecute (hstmt) != SQL_SUCCESS)
{
ODBC_Errors ("SQLExec");
continue;
}
}
totalSets = 1;
do
{
if (SQLNumResultCols (hstmt, &numCols) != SQL_SUCCESS)
{
ODBC_Errors ("SQLNumResultCols");
goto endCursor;
}
if (numCols == 0)
{
printf ("Statement executed.\n");
goto endCursor;
}
if (numCols > MAXCOLS)
numCols = MAXCOLS;
putchar ('\n');
for (colNum = 1; colNum <= numCols; colNum++)
{
if (SQLDescribeCol (hstmt, colNum, (UCHAR *) colName,
sizeof (colName), NULL, &colType, &colPrecision,
&colScale, &colNullable) != SQL_SUCCESS)
{
ODBC_Errors ("SQLDescribeCol");
goto endCursor;
}
switch (colType)
{
case SQL_VARCHAR:
case SQL_CHAR:
displayWidth = (short) colPrecision;
break;
case SQL_BIT:
displayWidth = 1;
break;
case SQL_TINYINT:
case SQL_SMALLINT:
case SQL_INTEGER:
case SQL_BIGINT:
displayWidth = colPrecision + 1;
break;
case SQL_DOUBLE:
case SQL_DECIMAL:
case SQL_NUMERIC:
case SQL_FLOAT:
case SQL_REAL:
displayWidth = colPrecision + 2;
break;
case SQL_DATE:
displayWidth = 10;
break;
case SQL_TIME:
displayWidth = 8;
break;
case SQL_TIMESTAMP:
displayWidth = 19;
break;
default:
displayWidths[colNum - 1] = 0;
continue;
}
if (displayWidth < strlen (colName))
displayWidth = strlen (colName);
if (displayWidth > sizeof (fetchBuffer) - 1)
displayWidth = sizeof (fetchBuffer) - 1;
displayWidths[colNum - 1] = displayWidth;
printf ("%-*.*s", displayWidth, displayWidth, colName);
if (colNum < numCols)
putchar ('|');
}
putchar ('\n');
for (colNum = 1; colNum <= numCols; colNum++)
{
for (i = 0; i < displayWidths[colNum - 1]; i++)
putchar ('-');
if (colNum < numCols)
putchar ('+');
}
putchar ('\n');
totalRows = 0;
while (1)
{
int sts = SQLFetch (hstmt);
if (sts == SQL_NO_DATA_FOUND)
break;
if (sts != SQL_SUCCESS)
{
ODBC_Errors ("Fetch");
break;
}
for (colNum = 1; colNum <= numCols; colNum++)
{
if (SQLGetData (hstmt, colNum, SQL_CHAR, fetchBuffer,
sizeof (fetchBuffer), &colIndicator) != SQL_SUCCESS)
{
ODBC_Errors ("SQLGetData");
goto endCursor;
}
if (colIndicator == SQL_NULL_DATA)
{
for (i = 0; i < displayWidths[colNum - 1]; i++)
fetchBuffer[i] = '*';
fetchBuffer[i] = '\0';
}
printf ("%-*.*s", displayWidths[colNum - 1],
displayWidths[colNum - 1], fetchBuffer);
if (colNum < numCols)
putchar ('|');
}
putchar ('\n');
totalRows++;
}
printf ("\n result set %lu returned %lu rows.\n\n",
totalSets, totalRows);
totalSets++;
}
while (SQLMoreResults (hstmt) == SQL_SUCCESS);
endCursor:
SQLFreeStmt (hstmt, SQL_CLOSE);
}
return 0;
}
int
main (int argc, char **argv)
{
printf ("iODBC Demonstration program\n");
printf ("This program shows an interactive SQL processor\n");
if (argc > 2 || (argc == 2 && argv[1][0] == '-'))
{
fprintf (stderr, "\nUsage:\n odbctest [\"DSN=xxxx;UID=xxxx;PWD=xxxx\"]\n");
exit(0);
}
if (ODBC_Connect (argv[1]) != 0)
{
ODBC_Errors ("ODBC_Connect");
}
else if (ODBC_Test () != 0)
{
ODBC_Errors ("ODBC_Test");
}
ODBC_Disconnect ();
printf ("\nHave a nice day.\n");
return 0;
}