iodbctest.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104
  1. /*
  2. * iodbctest.c
  3. *
  4. * $Id$
  5. *
  6. * Sample ODBC program
  7. *
  8. * The iODBC driver manager.
  9. *
  10. * Copyright (C) 1996-2021 OpenLink Software <[email protected]>
  11. * All Rights Reserved.
  12. *
  13. * This software is released under the terms of either of the following
  14. * licenses:
  15. *
  16. * - GNU Library General Public License (see LICENSE.LGPL)
  17. * - The BSD License (see LICENSE.BSD).
  18. *
  19. * Note that the only valid version of the LGPL license as far as this
  20. * project is concerned is the original GNU Library General Public License
  21. * Version 2, dated June 1991.
  22. *
  23. * While not mandated by the BSD license, any patches you make to the
  24. * iODBC source code may be contributed back into the iODBC project
  25. * at your discretion. Contributions will benefit the Open Source and
  26. * Data Access community as a whole. Submissions may be made at:
  27. *
  28. * http://www.iodbc.org
  29. *
  30. *
  31. * GNU Library Generic Public License Version 2
  32. * ============================================
  33. * This library is free software; you can redistribute it and/or
  34. * modify it under the terms of the GNU Library General Public
  35. * License as published by the Free Software Foundation; only
  36. * Version 2 of the License dated June 1991.
  37. *
  38. * This library is distributed in the hope that it will be useful,
  39. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  40. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  41. * Library General Public License for more details.
  42. *
  43. * You should have received a copy of the GNU Library General Public
  44. * License along with this library; if not, write to the Free
  45. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  46. *
  47. *
  48. * The BSD License
  49. * ===============
  50. * Redistribution and use in source and binary forms, with or without
  51. * modification, are permitted provided that the following conditions
  52. * are met:
  53. *
  54. * 1. Redistributions of source code must retain the above copyright
  55. * notice, this list of conditions and the following disclaimer.
  56. * 2. Redistributions in binary form must reproduce the above copyright
  57. * notice, this list of conditions and the following disclaimer in
  58. * the documentation and/or other materials provided with the
  59. * distribution.
  60. * 3. Neither the name of OpenLink Software Inc. nor the names of its
  61. * contributors may be used to endorse or promote products derived
  62. * from this software without specific prior written permission.
  63. *
  64. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  65. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  66. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  67. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR
  68. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  69. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  70. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  71. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  72. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  73. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  74. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  75. */
  76. #include <stdlib.h>
  77. #include <stdio.h>
  78. #include <string.h>
  79. #include <locale.h>
  80. #include <sql.h>
  81. #include <sqlext.h>
  82. #include <sqlucode.h>
  83. #include <iodbcext.h>
  84. /*
  85. * Prototypes
  86. */
  87. int ODBC_Connect (char *connStr);
  88. int ODBC_Disconnect (void);
  89. int ODBC_Errors (char *where);
  90. int ODBC_Test (void);
  91. #define MAXCOLS 32
  92. #ifdef UNICODE
  93. #define TEXT(x) (SQLWCHAR *) L##x
  94. #define TEXTC(x) (SQLWCHAR) L##x
  95. #define TXTLEN(x) wcslen((wchar_t *) x)
  96. #define TXTCMP(x1,x2) wcscmp((wchar_t *) x1, (wchar_t *) x2)
  97. # ifdef WIN32
  98. #define OPL_A2W(a, w, cb) \
  99. MultiByteToWideChar(CP_ACP, 0, a, -1, w, cb)
  100. # else
  101. #define OPL_A2W(XA, XW, SIZE) mbstowcs(XW, XA, SIZE)
  102. # endif /* WIN32 */
  103. #else
  104. #define TEXT(x) (SQLCHAR *) x
  105. #define TEXTC(x) (SQLCHAR) x
  106. #define TXTLEN(x) strlen((char *) x)
  107. #define TXTCMP(x1,x2) strcmp((char *) x1, (char *) x2)
  108. #endif /* UNICODE */
  109. #define NUMTCHAR(X) (sizeof (X) / sizeof (SQLTCHAR))
  110. /*
  111. * Global variables
  112. */
  113. HENV henv = SQL_NULL_HANDLE;
  114. HDBC hdbc = SQL_NULL_HANDLE;
  115. HSTMT hstmt = SQL_NULL_HANDLE;
  116. int connected = 0;
  117. /*
  118. * Unicode conversion routines
  119. */
  120. #ifdef UNICODE
  121. static SQLWCHAR *
  122. strcpy_A2W (SQLWCHAR * destStr, char *sourStr)
  123. {
  124. size_t length;
  125. if (!sourStr || !destStr)
  126. return destStr;
  127. length = strlen (sourStr);
  128. if (length > 0)
  129. OPL_A2W (sourStr, destStr, length);
  130. destStr[length] = L'\0';
  131. return destStr;
  132. }
  133. #endif
  134. /*
  135. * Connect to the datasource
  136. *
  137. * The connect string can have the following parts and they refer to
  138. * the values in the odbc.ini file
  139. *
  140. * DSN=<data source name> [mandatory]
  141. * HOST=<server host name> [optional - value of Host]
  142. * SVT=<database server type> [optional - value of ServerType]
  143. * DATABASE=<database path> [optional - value of Database]
  144. * OPTIONS=<db specific opts> [optional - value of Options]
  145. * UID=<user name> [optional - value of LastUser]
  146. * PWD=<password> [optional]
  147. * READONLY=<N|Y> [optional - value of ReadOnly]
  148. * FBS=<fetch buffer size> [optional - value of FetchBufferSize]
  149. *
  150. * Examples:
  151. *
  152. * HOST=star;SVT=SQLServer 2000;UID=demo;PWD=demo;DATABASE=pubs
  153. *
  154. * DSN=pubs_sqlserver;PWD=demo
  155. */
  156. SQLTCHAR outdsn[4096]; /* Store completed DSN for later use */
  157. int
  158. ODBC_Connect (char *connStr)
  159. {
  160. short buflen;
  161. SQLCHAR dataSource[1024];
  162. SQLTCHAR dsn[33];
  163. SQLTCHAR desc[255];
  164. SQLTCHAR driverInfo[255];
  165. SQLSMALLINT len1, len2;
  166. int status;
  167. #ifdef UNICODE
  168. SQLWCHAR wdataSource[1024];
  169. #endif
  170. #if (ODBCVER < 0x0300)
  171. if (SQLAllocEnv (&henv) != SQL_SUCCESS)
  172. return -1;
  173. # ifdef UNICODE
  174. SQLSetEnvAttr (henv, SQL_ATTR_APP_UNICODE_TYPE,
  175. (SQLPOINTER) SQL_DM_CP_DEF, SQL_IS_UINTEGER);
  176. #endif
  177. if (SQLAllocConnect (henv, &hdbc) != SQL_SUCCESS)
  178. return -1;
  179. #else
  180. if (SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv) != SQL_SUCCESS)
  181. return -1;
  182. SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3,
  183. SQL_IS_UINTEGER);
  184. # ifdef UNICODE
  185. SQLSetEnvAttr (henv, SQL_ATTR_APP_UNICODE_TYPE,
  186. (SQLPOINTER) SQL_DM_CP_DEF, SQL_IS_UINTEGER);
  187. #endif
  188. if (SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc) != SQL_SUCCESS)
  189. return -1;
  190. #endif
  191. /*
  192. * Set the application name
  193. */
  194. SQLSetConnectOption (hdbc, SQL_APPLICATION_NAME,
  195. (SQLULEN) TEXT ("odbctest"));
  196. /*
  197. * Show the version number of the driver manager
  198. */
  199. status = SQLGetInfo (hdbc, SQL_DM_VER,
  200. driverInfo, sizeof (driverInfo), &len1);
  201. if (status == SQL_SUCCESS)
  202. {
  203. #ifdef UNICODE
  204. printf ("Driver Manager: %S\n", driverInfo);
  205. #else
  206. printf ("Driver Manager: %s\n", driverInfo);
  207. #endif
  208. }
  209. /*
  210. * Either use the connect string provided on the command line or
  211. * ask for one. If an empty string or a ? is given, show a nice
  212. * list of options
  213. */
  214. if (connStr && *connStr)
  215. strcpy ((char *) dataSource, connStr);
  216. else
  217. while (1)
  218. {
  219. /*
  220. * Ask for the connect string
  221. */
  222. printf ("\nEnter ODBC connect string (? shows list): ");
  223. if (fgets ((char *) dataSource, sizeof (dataSource), stdin) == NULL)
  224. return 1;
  225. /*
  226. * Remove trailing '\n'
  227. */
  228. dataSource[strlen ((char *) dataSource) - 1] = '\0';
  229. /*
  230. * Check if the user wants to quit
  231. */
  232. if (!strcmp ((char *)dataSource, "quit") || !strcmp ((char *)dataSource, "exit"))
  233. return -1;
  234. /*
  235. * If the user entered something other than a ?
  236. * break out of the while loop
  237. */
  238. if (*dataSource && *dataSource != '?')
  239. break;
  240. /*
  241. * Print headers
  242. */
  243. fprintf (stderr, "\n%-32s | %-40s\n", "DSN", "Driver");
  244. fprintf (stderr,
  245. "------------------------------------------------------------------------------\n");
  246. /*
  247. * Goto the first record
  248. */
  249. if (SQLDataSources (henv, SQL_FETCH_FIRST,
  250. dsn, NUMTCHAR (dsn), &len1,
  251. desc, NUMTCHAR (desc), &len2) != SQL_SUCCESS)
  252. continue;
  253. /*
  254. * Show all records
  255. */
  256. do
  257. {
  258. #ifdef UNICODE
  259. fprintf (stderr, "%-32S | %-40S\n", dsn, desc);
  260. #else
  261. fprintf (stderr, "%-32s | %-40s\n", dsn, desc);
  262. #endif
  263. }
  264. while (SQLDataSources (henv, SQL_FETCH_NEXT,
  265. dsn, NUMTCHAR (dsn), &len1,
  266. desc, NUMTCHAR (desc), &len2) == SQL_SUCCESS);
  267. }
  268. #ifdef UNICODE
  269. strcpy_A2W (wdataSource, (char *) dataSource);
  270. status = SQLDriverConnectW (hdbc, 0, (SQLWCHAR *) wdataSource, SQL_NTS,
  271. (SQLWCHAR *) outdsn, NUMTCHAR (outdsn), &buflen, SQL_DRIVER_COMPLETE);
  272. if (status != SQL_SUCCESS)
  273. ODBC_Errors ("SQLDriverConnectW");
  274. #else
  275. status = SQLDriverConnect (hdbc, 0, (SQLCHAR *) dataSource, SQL_NTS,
  276. (SQLCHAR *) outdsn, NUMTCHAR (outdsn), &buflen, SQL_DRIVER_COMPLETE);
  277. if (status != SQL_SUCCESS)
  278. ODBC_Errors ("SQLDriverConnect");
  279. #endif
  280. if (status != SQL_SUCCESS && status != SQL_SUCCESS_WITH_INFO)
  281. return -1;
  282. connected = 1;
  283. /*
  284. * Print out the version number and the name of the connected driver
  285. */
  286. status = SQLGetInfo (hdbc, SQL_DRIVER_VER,
  287. driverInfo, NUMTCHAR (driverInfo), &len1);
  288. if (status == SQL_SUCCESS)
  289. {
  290. #ifdef UNICODE
  291. printf ("Driver: %S", driverInfo);
  292. #else
  293. printf ("Driver: %s", driverInfo);
  294. #endif
  295. status = SQLGetInfo (hdbc, SQL_DRIVER_NAME,
  296. driverInfo, NUMTCHAR (driverInfo), &len1);
  297. if (status == SQL_SUCCESS)
  298. {
  299. #ifdef UNICODE
  300. printf (" (%S)", driverInfo);
  301. #else
  302. printf (" (%s)", driverInfo);
  303. #endif
  304. }
  305. printf ("\n");
  306. }
  307. /*
  308. * Show the list of supported functions in trace log
  309. */
  310. #if (ODBCVER < 0x0300)
  311. {
  312. SQLUSMALLINT exists[100];
  313. SQLGetFunctions (hdbc, SQL_API_ALL_FUNCTIONS, exists);
  314. }
  315. #else
  316. {
  317. SQLUSMALLINT exists[SQL_API_ODBC3_ALL_FUNCTIONS_SIZE];
  318. SQLGetFunctions (hdbc, SQL_API_ODBC3_ALL_FUNCTIONS, exists);
  319. }
  320. #endif
  321. /*
  322. * Allocate statement handle
  323. */
  324. #if (ODBCVER < 0x0300)
  325. if (SQLAllocStmt (hdbc, &hstmt) != SQL_SUCCESS)
  326. return -1;
  327. #else
  328. if (SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt) != SQL_SUCCESS)
  329. return -1;
  330. #endif
  331. return 0;
  332. }
  333. /*
  334. * Disconnect from the database
  335. */
  336. int
  337. ODBC_Disconnect (void)
  338. {
  339. #if (ODBCVER < 0x0300)
  340. if (hstmt)
  341. SQLFreeStmt (hstmt, SQL_DROP);
  342. if (connected)
  343. SQLDisconnect (hdbc);
  344. if (hdbc)
  345. SQLFreeConnect (hdbc);
  346. if (henv)
  347. SQLFreeEnv (henv);
  348. #else
  349. if (hstmt)
  350. {
  351. SQLCloseCursor (hstmt);
  352. SQLFreeHandle (SQL_HANDLE_STMT, hstmt);
  353. }
  354. if (connected)
  355. SQLDisconnect (hdbc);
  356. if (hdbc)
  357. SQLFreeHandle (SQL_HANDLE_DBC, hdbc);
  358. if (henv)
  359. SQLFreeHandle (SQL_HANDLE_ENV, henv);
  360. #endif
  361. return 0;
  362. }
  363. /*
  364. * Perform a disconnect/reconnect using the DSN stored from the original
  365. * SQLDriverConnect
  366. */
  367. int
  368. ODBC_Reconnect (void)
  369. {
  370. SQLRETURN status;
  371. SQLTCHAR buf[4096];
  372. SQLSMALLINT len;
  373. /*
  374. * Free old statement handle
  375. */
  376. #if (ODBCVER < 0x0300)
  377. SQLFreeStmt (hstmt, SQL_DROP);
  378. #else
  379. SQLFreeHandle (SQL_HANDLE_STMT, hstmt);
  380. #endif
  381. /*
  382. * Disconnect
  383. */
  384. SQLDisconnect (hdbc);
  385. /*
  386. * Reconnect
  387. */
  388. status = SQLDriverConnect (hdbc, 0, outdsn, SQL_NTS,
  389. buf, sizeof (buf), &len, SQL_DRIVER_NOPROMPT);
  390. /*
  391. * Allocate new statement handle
  392. */
  393. if (SQL_SUCCEEDED (status))
  394. {
  395. #if (ODBCVER < 0x0300)
  396. status = SQLAllocStmt (hdbc, &hstmt);
  397. #else
  398. status = SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt);
  399. #endif
  400. }
  401. /*
  402. * Show why we where unsuccessful and return an error
  403. */
  404. if (!SQL_SUCCEEDED (status))
  405. {
  406. ODBC_Errors ("DriverConnect (reconnect)");
  407. return -1;
  408. }
  409. /*
  410. * Success
  411. */
  412. return 0;
  413. }
  414. /*
  415. * Show all the error information that is available
  416. */
  417. int
  418. ODBC_Errors (char *where)
  419. {
  420. SQLTCHAR buf[512];
  421. SQLTCHAR sqlstate[15];
  422. SQLINTEGER native_error = 0;
  423. int force_exit = 0;
  424. SQLRETURN sts;
  425. #if (ODBCVER < 0x0300)
  426. /*
  427. * Get statement errors
  428. */
  429. while (hstmt)
  430. {
  431. sts = SQLError (henv, hdbc, hstmt, sqlstate, &native_error,
  432. buf, NUMTCHAR (buf), NULL);
  433. if (!SQL_SUCCEEDED (sts))
  434. break;
  435. #ifdef UNICODE
  436. fprintf (stderr, "%s = %S (%ld) SQLSTATE=%S\n",
  437. where, buf, (long) native_error, sqlstate);
  438. #else
  439. fprintf (stderr, "%s = %s (%ld) SQLSTATE=%s\n",
  440. where, buf, (long) native_error, sqlstate);
  441. #endif
  442. /*
  443. * If the driver could not be loaded, there is no point in
  444. * continuing, after reading all the error messages
  445. */
  446. if (!TXTCMP (sqlstate, TEXT ("IM003")))
  447. force_exit = 1;
  448. }
  449. /*
  450. * Get connection errors
  451. */
  452. while (hdbc)
  453. {
  454. sts = SQLError (henv, hdbc, SQL_NULL_HSTMT, sqlstate, &native_error,
  455. buf, NUMTCHAR (buf), NULL);
  456. if (!SQL_SUCCEEDED (sts))
  457. break;
  458. #ifdef UNICODE
  459. fprintf (stderr, "%s = %S (%ld) SQLSTATE=%S\n",
  460. where, buf, (long) native_error, sqlstate);
  461. #else
  462. fprintf (stderr, "%s = %s (%ld) SQLSTATE=%s\n",
  463. where, buf, (long) native_error, sqlstate);
  464. #endif
  465. /*
  466. * If the driver could not be loaded, there is no point in
  467. * continuing, after reading all the error messages
  468. */
  469. if (!TXTCMP (sqlstate, TEXT ("IM003")))
  470. force_exit = 1;
  471. }
  472. /*
  473. * Get environment errors
  474. */
  475. while (henv)
  476. {
  477. sts SQLError (henv, SQL_NULL_HDBC, SQL_NULL_HSTMT, sqlstate,
  478. &native_error, buf, NUMTCHAR (buf), NULL);
  479. if (!SQL_SUCCEEDED (sts))
  480. break;
  481. #ifdef UNICODE
  482. fprintf (stderr, "%s = %S (%ld) SQLSTATE=%S\n",
  483. where, buf, (long) native_error, sqlstate);
  484. #else
  485. fprintf (stderr, "%s = %s (%ld) SQLSTATE=%s\n",
  486. where, buf, (long) native_error, sqlstate);
  487. #endif
  488. /*
  489. * If the driver could not be loaded, there is no point in
  490. * continuing, after reading all the error messages
  491. */
  492. if (!TXTCMP (sqlstate, TEXT ("IM003")))
  493. force_exit = 1;
  494. }
  495. #else /* ODBCVER */
  496. int i;
  497. /*
  498. * Get statement errors
  499. */
  500. i = 0;
  501. while (hstmt && i < 5)
  502. {
  503. sts = SQLGetDiagRec (SQL_HANDLE_STMT, hstmt, ++i,
  504. sqlstate, &native_error, buf, NUMTCHAR (buf), NULL);
  505. if (!SQL_SUCCEEDED (sts))
  506. break;
  507. #ifdef UNICODE
  508. fprintf (stderr, "%d: %s = %S (%ld) SQLSTATE=%S\n",
  509. i, where, buf, (long) native_error, sqlstate);
  510. #else
  511. fprintf (stderr, "%d: %s = %s (%ld) SQLSTATE=%s\n",
  512. i, where, buf, (long) native_error, sqlstate);
  513. #endif
  514. /*
  515. * If the driver could not be loaded, there is no point in
  516. * continuing, after reading all the error messages
  517. */
  518. if (!TXTCMP (sqlstate, TEXT ("IM003")))
  519. force_exit = 1;
  520. }
  521. /*
  522. * Get connection errors
  523. */
  524. i = 0;
  525. while (hdbc && i < 5)
  526. {
  527. sts = SQLGetDiagRec (SQL_HANDLE_DBC, hdbc, ++i,
  528. sqlstate, &native_error, buf, NUMTCHAR (buf), NULL);
  529. if (!SQL_SUCCEEDED (sts))
  530. break;
  531. #ifdef UNICODE
  532. fprintf (stderr, "%d: %s = %S (%ld) SQLSTATE=%S\n",
  533. i, where, buf, (long) native_error, sqlstate);
  534. #else
  535. fprintf (stderr, "%d: %s = %s (%ld) SQLSTATE=%s\n",
  536. i, where, buf, (long) native_error, sqlstate);
  537. #endif
  538. /*
  539. * If the driver could not be loaded, there is no point in
  540. * continuing, after reading all the error messages
  541. */
  542. if (!TXTCMP (sqlstate, TEXT ("IM003")))
  543. force_exit = 1;
  544. }
  545. /*
  546. * Get environment errors
  547. */
  548. i = 0;
  549. while (henv && i < 5)
  550. {
  551. sts = SQLGetDiagRec (SQL_HANDLE_ENV, henv, ++i,
  552. sqlstate, &native_error, buf, NUMTCHAR (buf), NULL);
  553. if (!SQL_SUCCEEDED (sts))
  554. break;
  555. #ifdef UNICODE
  556. fprintf (stderr, "%d: %s = %S (%ld) SQLSTATE=%S\n",
  557. i, where, buf, (long) native_error, sqlstate);
  558. #else
  559. fprintf (stderr, "%d: %s = %s (%ld) SQLSTATE=%s\n",
  560. i, where, buf, (long) native_error, sqlstate);
  561. #endif
  562. /*
  563. * If the driver could not be loaded, there is no point in
  564. * continuing, after reading all the error messages
  565. */
  566. if (!TXTCMP (sqlstate, TEXT ("IM003")))
  567. force_exit = 1;
  568. }
  569. #endif /* ODBCVER */
  570. /*
  571. * Force an exit status
  572. */
  573. if (force_exit)
  574. exit (-1);
  575. return -1;
  576. }
  577. /*
  578. * Test program to run on the connected database
  579. */
  580. int
  581. ODBC_Test ()
  582. {
  583. SQLTCHAR request[4096];
  584. SQLTCHAR fetchBuffer[1024];
  585. char buf[4096];
  586. int displayWidths[MAXCOLS];
  587. int displayWidth;
  588. short numCols;
  589. short colNum;
  590. SQLTCHAR colName[50];
  591. SQLSMALLINT colType;
  592. SQLULEN colPrecision;
  593. SQLLEN colIndicator;
  594. SQLSMALLINT colScale;
  595. SQLSMALLINT colNullable;
  596. unsigned long totalRows;
  597. unsigned long totalSets;
  598. int i;
  599. SQLRETURN sts;
  600. while (1)
  601. {
  602. /*
  603. * Ask the user for a dynamic SQL statement
  604. */
  605. printf ("\nSQL>");
  606. if (fgets (buf, sizeof (buf), stdin) == NULL)
  607. break;
  608. #ifndef UNICODE
  609. strcpy ((char *) request, (char *) buf);
  610. #else
  611. strcpy_A2W (request, buf);
  612. #endif
  613. request[TXTLEN (request) - 1] = TEXTC ('\0');
  614. if (request[0] == TEXTC ('\0'))
  615. continue;
  616. /*
  617. * If the user just types tables, give him a list
  618. */
  619. if (!TXTCMP (request, TEXT ("tables")))
  620. {
  621. if (SQLTables (hstmt, NULL, 0, NULL, 0, NULL, 0,
  622. NULL, 0) != SQL_SUCCESS)
  623. {
  624. ODBC_Errors ("SQLTables(tables)");
  625. continue;
  626. }
  627. }
  628. /*
  629. * If the user just types qualifiers, give him a list
  630. */
  631. else if (!TXTCMP (request, TEXT ("qualifiers")))
  632. {
  633. if (SQLTables (hstmt, TEXT ("%"), SQL_NTS, TEXT (""), 0,
  634. TEXT (""), 0, TEXT (""), 0) != SQL_SUCCESS)
  635. {
  636. ODBC_Errors ("SQLTables(qualifiers)");
  637. continue;
  638. }
  639. }
  640. /*
  641. * If the user just types owners, give him a list
  642. */
  643. else if (!TXTCMP (request, TEXT ("owners")))
  644. {
  645. if (SQLTables (hstmt, TEXT (""), 0, TEXT ("%"), SQL_NTS,
  646. TEXT (""), 0, TEXT (""), 0) != SQL_SUCCESS)
  647. {
  648. ODBC_Errors ("SQLTables(owners)");
  649. continue;
  650. }
  651. }
  652. /*
  653. * If the user just types "types", give him a list
  654. */
  655. else if (!TXTCMP (request, TEXT ("types")))
  656. {
  657. if (SQLTables (hstmt, TEXT (""), 0, TEXT (""), 0,
  658. TEXT (""), 0, TEXT ("%"), SQL_NTS) != SQL_SUCCESS)
  659. {
  660. ODBC_Errors ("SQLTables(types)");
  661. continue;
  662. }
  663. }
  664. /*
  665. * If the user just types "datatypes", give him a list
  666. */
  667. else if (!TXTCMP (request, TEXT ("datatypes")))
  668. {
  669. if (SQLGetTypeInfo (hstmt, 0) != SQL_SUCCESS)
  670. {
  671. ODBC_Errors ("SQLGetTypeInfo");
  672. continue;
  673. }
  674. }
  675. else if (!TXTCMP (request, TEXT ("reconnect")))
  676. {
  677. if (ODBC_Reconnect())
  678. return -1;
  679. continue;
  680. }
  681. #if defined (unix)
  682. else if (!TXTCMP (request, TEXT ("environment")))
  683. {
  684. extern char **environ;
  685. for (i = 0; environ[i]; i++)
  686. fprintf (stderr, "%03d: [%s]\n", i, environ[i]);
  687. continue;
  688. }
  689. #endif
  690. else if (!TXTCMP (request, TEXT ("quit"))
  691. || !TXTCMP (request, TEXT ("exit")))
  692. break; /* If you want to quit, just say so */
  693. else
  694. {
  695. /*
  696. * Prepare & Execute the statement
  697. */
  698. if (SQLPrepare (hstmt, (SQLTCHAR *) request,
  699. SQL_NTS) != SQL_SUCCESS)
  700. {
  701. ODBC_Errors ("SQLPrepare");
  702. continue;
  703. }
  704. if ((sts = SQLExecute (hstmt)) != SQL_SUCCESS)
  705. {
  706. ODBC_Errors ("SQLExec");
  707. if (sts != SQL_SUCCESS_WITH_INFO)
  708. continue;
  709. }
  710. }
  711. /*
  712. * Loop through all the result sets
  713. */
  714. totalSets = 1;
  715. do
  716. {
  717. /*
  718. * Get the number of result columns for this cursor.
  719. * If it is 0, then the statement was probably a select
  720. */
  721. if (SQLNumResultCols (hstmt, &numCols) != SQL_SUCCESS)
  722. {
  723. ODBC_Errors ("SQLNumResultCols");
  724. goto endCursor;
  725. }
  726. if (numCols == 0)
  727. {
  728. SQLLEN nrows = 0;
  729. SQLRowCount (hstmt, &nrows);
  730. printf ("Statement executed. %ld rows affected.\n",
  731. nrows > 0 ? (long) nrows : 0L);
  732. goto endCursor;
  733. }
  734. if (numCols > MAXCOLS)
  735. {
  736. numCols = MAXCOLS;
  737. fprintf (stderr,
  738. "NOTE: Resultset truncated to %d columns.\n", MAXCOLS);
  739. }
  740. /*
  741. * Get the names for the columns
  742. */
  743. putchar ('\n');
  744. for (colNum = 1; colNum <= numCols; colNum++)
  745. {
  746. /*
  747. * Get the name and other type information
  748. */
  749. if (SQLDescribeCol (hstmt, colNum,
  750. (SQLTCHAR *) colName, NUMTCHAR (colName), NULL,
  751. &colType, &colPrecision, &colScale,
  752. &colNullable) != SQL_SUCCESS)
  753. {
  754. ODBC_Errors ("SQLDescribeCol");
  755. goto endCursor;
  756. }
  757. /*
  758. * Calculate the display width for the column
  759. */
  760. switch (colType)
  761. {
  762. case SQL_VARCHAR:
  763. case SQL_CHAR:
  764. case SQL_WVARCHAR:
  765. case SQL_WCHAR:
  766. case SQL_GUID:
  767. displayWidth = colPrecision;
  768. break;
  769. case SQL_BINARY:
  770. displayWidth = colPrecision * 2;
  771. break;
  772. case SQL_LONGVARCHAR:
  773. case SQL_WLONGVARCHAR:
  774. case SQL_LONGVARBINARY:
  775. displayWidth = 30; /* show only first 30 */
  776. break;
  777. case SQL_BIT:
  778. displayWidth = 1;
  779. break;
  780. case SQL_TINYINT:
  781. case SQL_SMALLINT:
  782. case SQL_INTEGER:
  783. case SQL_BIGINT:
  784. displayWidth = colPrecision + 1; /* sign */
  785. break;
  786. case SQL_DOUBLE:
  787. case SQL_DECIMAL:
  788. case SQL_NUMERIC:
  789. case SQL_FLOAT:
  790. case SQL_REAL:
  791. displayWidth = colPrecision + 2; /* sign, comma */
  792. break;
  793. #ifdef SQL_TYPE_DATE
  794. case SQL_TYPE_DATE:
  795. #endif
  796. case SQL_DATE:
  797. displayWidth = 10;
  798. break;
  799. #ifdef SQL_TYPE_TIME
  800. case SQL_TYPE_TIME:
  801. #endif
  802. case SQL_TIME:
  803. displayWidth = 8;
  804. break;
  805. #ifdef SQL_TYPE_TIMESTAMP
  806. case SQL_TYPE_TIMESTAMP:
  807. #endif
  808. case SQL_TIMESTAMP:
  809. displayWidth = 19;
  810. if (colScale > 0)
  811. displayWidth = displayWidth + colScale + 1;
  812. break;
  813. default:
  814. displayWidths[colNum - 1] = 0; /* skip other data types */
  815. continue;
  816. }
  817. if (displayWidth < TXTLEN (colName))
  818. displayWidth = TXTLEN (colName);
  819. if (displayWidth > NUMTCHAR (fetchBuffer) - 1)
  820. displayWidth = NUMTCHAR (fetchBuffer) - 1;
  821. displayWidths[colNum - 1] = displayWidth;
  822. /*
  823. * Print header field
  824. */
  825. #ifdef UNICODE
  826. printf ("%-*.*S", displayWidth, displayWidth, colName);
  827. #else
  828. printf ("%-*.*s", displayWidth, displayWidth, colName);
  829. #endif
  830. if (colNum < numCols)
  831. putchar ('|');
  832. }
  833. putchar ('\n');
  834. /*
  835. * Print second line
  836. */
  837. for (colNum = 1; colNum <= numCols; colNum++)
  838. {
  839. for (i = 0; i < displayWidths[colNum - 1]; i++)
  840. putchar ('-');
  841. if (colNum < numCols)
  842. putchar ('+');
  843. }
  844. putchar ('\n');
  845. /*
  846. * Print all the fields
  847. */
  848. totalRows = 0;
  849. while (1)
  850. {
  851. #if (ODBCVER < 0x0300)
  852. sts = SQLFetch (hstmt);
  853. #else
  854. sts = SQLFetchScroll (hstmt, SQL_FETCH_NEXT, 1);
  855. #endif
  856. if (sts == SQL_NO_DATA_FOUND)
  857. break;
  858. if (sts != SQL_SUCCESS)
  859. {
  860. ODBC_Errors ("Fetch");
  861. break;
  862. }
  863. for (colNum = 1; colNum <= numCols; colNum++)
  864. {
  865. /*
  866. * Fetch this column as character
  867. */
  868. #ifdef UNICODE
  869. sts = SQLGetData (hstmt, colNum, SQL_C_WCHAR, fetchBuffer,
  870. NUMTCHAR (fetchBuffer), &colIndicator);
  871. #else
  872. sts = SQLGetData (hstmt, colNum, SQL_C_CHAR, fetchBuffer,
  873. NUMTCHAR (fetchBuffer), &colIndicator);
  874. #endif
  875. if (sts != SQL_SUCCESS_WITH_INFO && sts != SQL_SUCCESS)
  876. {
  877. ODBC_Errors ("SQLGetData");
  878. goto endCursor;
  879. }
  880. /*
  881. * Show NULL fields as ****
  882. */
  883. if (colIndicator == SQL_NULL_DATA)
  884. {
  885. for (i = 0; i < displayWidths[colNum - 1]; i++)
  886. fetchBuffer[i] = TEXTC ('*');
  887. fetchBuffer[i] = TEXTC ('\0');
  888. }
  889. #ifdef UNICODE
  890. printf ("%-*.*S", displayWidths[colNum - 1],
  891. displayWidths[colNum - 1], fetchBuffer);
  892. #else
  893. printf ("%-*.*s", displayWidths[colNum - 1],
  894. displayWidths[colNum - 1], fetchBuffer);
  895. #endif
  896. if (colNum < numCols)
  897. putchar ('|');
  898. }
  899. putchar ('\n');
  900. totalRows++;
  901. }
  902. printf ("\n result set %lu returned %lu rows.\n\n",
  903. totalSets, totalRows);
  904. totalSets++;
  905. }
  906. while ((sts = SQLMoreResults (hstmt)) == SQL_SUCCESS);
  907. if (sts == SQL_ERROR)
  908. ODBC_Errors ("SQLMoreResults");
  909. endCursor:
  910. #if (ODBCVER < 0x0300)
  911. SQLFreeStmt (hstmt, SQL_CLOSE);
  912. #else
  913. SQLCloseCursor (hstmt);
  914. #endif
  915. }
  916. return 0;
  917. }
  918. int
  919. main (int argc, char **argv)
  920. {
  921. /*
  922. * Set locale based on environment variables
  923. */
  924. setlocale (LC_ALL, "");
  925. /*
  926. * Show welcome message
  927. */
  928. #ifdef UNICODE
  929. printf ("iODBC Unicode Demonstration program\n");
  930. #else
  931. printf ("iODBC Demonstration program\n");
  932. #endif
  933. printf ("This program shows an interactive SQL processor\n");
  934. /*
  935. * Show a usage string when the user asks for this
  936. */
  937. if (argc > 2 || (argc == 2 && argv[1][0] == '-'))
  938. {
  939. fprintf (stderr,
  940. "\nUsage:\n iodbctest [\"DSN=xxxx;UID=xxxx;PWD=xxxx\"]\n");
  941. exit (0);
  942. }
  943. /*
  944. * If we can connect to this datasource, run the test program
  945. */
  946. if (ODBC_Connect (argv[1]) != 0)
  947. {
  948. ODBC_Errors ("ODBC_Connect");
  949. }
  950. else if (ODBC_Test () != 0)
  951. {
  952. ODBC_Errors ("ODBC_Test");
  953. }
  954. /*
  955. * End the connection
  956. */
  957. ODBC_Disconnect ();
  958. printf ("\nHave a nice day.");
  959. return 0;
  960. }