00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00037 #include "config.h"
00038 #include "perr.h"
00039
00040 #ifdef USE_ODBC
00041
00042 #include <glib.h>
00043 #include <sql.h>
00044 #include <sqlext.h>
00045 #include <string.h>
00046
00047 #include "dui-initdb-p.h"
00048 #include "dui-odbc.h"
00049
00050 typedef struct DuiODBCConnection_s DuiODBCConnection;
00051 typedef struct DuiODBCRecordSet_s DuiODBCRecordSet;
00052
00053 struct DuiODBCConnection_s
00054 {
00055 DuiDBConnection dbcon;
00056 const char * dbname;
00057 const char * username;
00058 SQLHENV sql_henv;
00059 SQLHDBC sql_hdbc;
00060
00061 GList * free_pool;
00062 };
00063
00064 struct DuiODBCRecordSet_s
00065 {
00066 DuiDBRecordSet recset;
00067 DuiODBCConnection *conn;
00068 SQLHSTMT sql_hstmt;
00069
00070 gint ncols;
00071 gint arrsize;
00072 gchar **column_labels;
00073 gint *column_datatype;
00074 gchar **values;
00075 gint *vsizes;
00076 };
00077
00078 static void dui_odbc_recordset_free (DuiODBCRecordSet *rs);
00079
00080
00081
00082 #define PRINT_SQLERR(HTYPE,HAN) \
00083 { \
00084 guchar sql_stat[10]; \
00085 SQLSMALLINT msglen; \
00086 SQLINTEGER err; \
00087 guchar msg[200]; \
00088 \
00089 SQLGetDiagRec(HTYPE, HAN, 1, sql_stat, \
00090 &err, msg, sizeof(msg), &msglen); \
00091 PERR("(%d) %s\n", err, msg); \
00092 }
00093
00094
00095
00096
00097 DuiDBConnection *
00098 dui_odbc_connection_new (const gchar * dbname,
00099 const gchar * username,
00100 const gchar * authentication)
00101 {
00102 SQLRETURN rc;
00103 DuiODBCConnection *conn;
00104
00105 ENTER ("(dbname=%s, username=%s)", dbname, username);
00106 if (NULL == dbname) return NULL;
00107
00108 conn = g_new (DuiODBCConnection, 1);
00109
00110 conn->free_pool = NULL;
00111
00112
00113 rc = SQLAllocEnv(&conn->sql_henv);
00114 if ((SQL_SUCCESS != rc) && (SQL_SUCCESS_WITH_INFO != rc))
00115 {
00116 PERR("Can't SQLAllocEnv, rc=%d", rc);
00117 g_free (conn);
00118 return NULL;
00119 }
00120
00121
00122
00123 rc = SQLSetEnvAttr(conn->sql_henv, SQL_ATTR_ODBC_VERSION,
00124 (void*)SQL_OV_ODBC3, 0);
00125 if ((SQL_SUCCESS != rc) && (SQL_SUCCESS_WITH_INFO != rc))
00126 {
00127 PERR("Can't SQLSetEnv, rc=%d", rc);
00128 PRINT_SQLERR (SQL_HANDLE_ENV, conn->sql_henv);
00129 SQLFreeHandle(SQL_HANDLE_ENV, conn->sql_henv);
00130 g_free (conn);
00131 return NULL;
00132 }
00133
00134
00135 rc = SQLAllocConnect(conn->sql_henv, &conn->sql_hdbc);
00136 if ((SQL_SUCCESS != rc) && (SQL_SUCCESS_WITH_INFO != rc))
00137 {
00138 PERR ("Can't SQLAllocConnect handle rc=%d", rc);
00139 PRINT_SQLERR (SQL_HANDLE_ENV, conn->sql_henv);
00140 SQLFreeHandle(SQL_HANDLE_ENV, conn->sql_henv);
00141 g_free (conn);
00142 return NULL;
00143 }
00144
00145
00146 SQLSetConnectAttr(conn->sql_hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0);
00147
00148 if (NULL == authentication) authentication = "";
00149 rc = SQLConnect(conn->sql_hdbc,
00150 (SQLCHAR*) dbname, SQL_NTS,
00151 (SQLCHAR*) username, SQL_NTS,
00152 (SQLCHAR*) authentication, SQL_NTS);
00153
00154 if ((SQL_SUCCESS != rc) && (SQL_SUCCESS_WITH_INFO != rc))
00155 {
00156 PERR ("Can't perform SQLConnect rc=%d", rc);
00157 PRINT_SQLERR (SQL_HANDLE_DBC, conn->sql_hdbc);
00158 SQLFreeHandle(SQL_HANDLE_DBC, conn->sql_hdbc);
00159 SQLFreeHandle(SQL_HANDLE_ENV, conn->sql_henv);
00160 return NULL;
00161 }
00162
00163 conn->dbname = g_strdup (dbname);
00164 conn->username = g_strdup (username);
00165
00166 LEAVE ("(dbname=%s, username=%s)", dbname, username);
00167 return &conn->dbcon;
00168 }
00169
00170
00171
00172 void
00173 dui_odbc_connection_free (DuiDBConnection *dbc)
00174 {
00175 DuiODBCConnection *conn = (DuiODBCConnection *) dbc;
00176 GList *node;
00177
00178 if (!conn) return;
00179
00180 if (conn->dbname) g_free ((gchar *) conn->dbname);
00181 conn->dbname = NULL;
00182
00183 if (conn->username) g_free ((gchar *) conn->username);
00184 conn->username = NULL;
00185
00186 SQLDisconnect(conn->sql_hdbc);
00187 SQLFreeHandle(SQL_HANDLE_DBC, conn->sql_hdbc);
00188 conn->sql_hdbc = NULL;
00189
00190 SQLFreeHandle(SQL_HANDLE_ENV, conn->sql_henv);
00191 conn->sql_henv = NULL;
00192
00193 for (node=conn->free_pool; node; node=node->next)
00194 {
00195 dui_odbc_recordset_free (node->data);
00196 }
00197 g_list_free (conn->free_pool);
00198 conn -> free_pool = NULL;
00199 }
00200
00201
00202
00203 #define DEFAULT_VARCHAR_SIZE 4040
00204
00205 static void
00206 dui_odbc_recordset_alloc_and_bind_cols (DuiODBCRecordSet *rs, gint ncols)
00207 {
00208 SQLLEN err;
00209 SQLRETURN rc;
00210 gint i;
00211
00212 if (ncols > rs->arrsize)
00213 {
00214 rs->column_labels = g_renew (gchar *, rs->column_labels, ncols);
00215 rs->column_datatype = g_renew (gint, rs->column_datatype, ncols);
00216 rs->values = g_renew (gchar *, rs->values, ncols);
00217 rs->vsizes = g_renew (gint, rs->vsizes, ncols);
00218
00219
00220 for (i = rs->arrsize; i<ncols; i++)
00221 {
00222 rs->column_labels[i] = NULL;
00223 rs->column_datatype[i] = 0;
00224 rs->values[i] = NULL;
00225 rs->vsizes[i] = 0;
00226 }
00227 rs->arrsize = ncols;
00228 }
00229
00230 for (i=0; i<ncols; i++)
00231 {
00232 if (rs->column_labels[i]) g_free (rs->column_labels[i]);
00233 rs->column_labels[i] = NULL;
00234 rs->column_datatype[i] = 0;
00235
00236 if (NULL == rs->values[i])
00237 {
00238 rs->values[i] = g_new (gchar, DEFAULT_VARCHAR_SIZE);
00239 rs->vsizes[i] = DEFAULT_VARCHAR_SIZE;
00240 rs->values[i][0] = 0;
00241 }
00242 rc = SQLBindCol(rs->sql_hstmt, i+1, SQL_C_CHAR,
00243 rs->values[i], rs->vsizes[i], &err);
00244 if ((SQL_SUCCESS != rc) && (SQL_SUCCESS_WITH_INFO != rc))
00245 {
00246 PERR ("Can't bind col=%d rc=%d", i, rc);
00247 PRINT_SQLERR (SQL_HANDLE_STMT, rs->sql_hstmt);
00248 return;
00249 }
00250 }
00251 }
00252
00253
00254
00255
00256 #define DEFAULT_NUM_COLS 50
00257
00258 static DuiODBCRecordSet *
00259 dui_odbc_recordset_new (DuiODBCConnection *conn)
00260 {
00261 SQLRETURN rc;
00262 DuiODBCRecordSet *rs;
00263
00264 if (!conn) return NULL;
00265 if (conn->free_pool)
00266 {
00267 rs = conn->free_pool->data;
00268 conn->free_pool = g_list_remove (conn->free_pool, rs);
00269 rs->ncols = -1;
00270 }
00271 else
00272 {
00273
00274 rs = g_new (DuiODBCRecordSet, 1);
00275 rs->conn = conn;
00276
00277 rs->ncols = -1;
00278 rs->arrsize = 0;
00279 rs->column_labels = NULL;
00280 rs->column_datatype = NULL;
00281 rs->values = NULL;
00282 rs->vsizes = NULL;
00283 }
00284
00285 rc = SQLAllocStmt (conn->sql_hdbc, &rs->sql_hstmt);
00286 if ((SQL_SUCCESS != rc) && (SQL_SUCCESS_WITH_INFO != rc))
00287 {
00288 PERR("Can't allocate statment handle, rc=%d", rc);
00289 PRINT_SQLERR (SQL_HANDLE_STMT, rs->sql_hstmt);
00290
00291 return NULL;
00292 }
00293
00294 dui_odbc_recordset_alloc_and_bind_cols (rs, DEFAULT_NUM_COLS);
00295
00296 return rs;
00297 }
00298
00299
00300
00301 void
00302 dui_odbc_recordset_release (DuiDBRecordSet *recset)
00303 {
00304 DuiODBCRecordSet *rs = (DuiODBCRecordSet *) recset;
00305 if (!rs) return;
00306
00307 SQLFreeHandle(SQL_HANDLE_STMT, rs->sql_hstmt);
00308 rs->sql_hstmt = NULL;
00309
00310 rs->conn->free_pool = g_list_prepend (rs->conn->free_pool, rs);
00311
00312 }
00313
00314
00315
00316 static void
00317 dui_odbc_recordset_free (DuiODBCRecordSet *rs)
00318 {
00319 gint i;
00320
00321 if (!rs) return;
00322
00323 rs->conn = NULL;
00324
00325 for (i=0; i<rs->arrsize; i++)
00326 {
00327 g_free (rs->column_labels[i]);
00328 g_free (rs->values[i]);
00329 }
00330 g_free (rs->column_labels);
00331 rs->column_labels = NULL;
00332
00333 g_free (rs->column_datatype);
00334 rs->column_datatype = NULL;
00335
00336 g_free (rs->values);
00337 rs->values = NULL;
00338
00339 g_free (rs->vsizes);
00340 rs->vsizes = NULL;
00341
00342 g_free (rs);
00343 }
00344
00345
00346
00347 DuiDBRecordSet *
00348 dui_odbc_connection_exec (DuiDBConnection *dbc, const char * buff)
00349 {
00350 DuiODBCConnection *conn = (DuiODBCConnection *) dbc;
00351 DuiODBCRecordSet *rs;
00352 SQLRETURN rc;
00353
00354 ENTER ("(conn=%p, buff=%s)", conn, buff);
00355 g_return_val_if_fail (conn, NULL);
00356
00357 rs = dui_odbc_recordset_new (conn);
00358 g_return_val_if_fail (rs, NULL);
00359
00360 rc = SQLExecDirect(rs->sql_hstmt, (guchar *)buff, SQL_NTS);
00361
00362 if ((SQL_SUCCESS != rc) && (SQL_SUCCESS_WITH_INFO != rc))
00363 {
00364 PERR ("Can't perform query rc=%d", rc);
00365 PRINT_SQLERR (SQL_HANDLE_STMT, rs->sql_hstmt);
00366 dui_odbc_recordset_release (&rs->recset);
00367 return NULL;
00368 }
00369
00370 LEAVE ("(conn=%p, buff=%s)", conn, buff);
00371
00372
00373 rs->ncols = -1;
00374 return &rs->recset;
00375 }
00376
00377
00378
00379
00380 DuiDBRecordSet *
00381 dui_odbc_connection_tables (DuiDBConnection *dbc)
00382 {
00383 DuiODBCConnection *conn = (DuiODBCConnection *) dbc;
00384 DuiODBCRecordSet *rs;
00385 SQLRETURN rc;
00386
00387 ENTER ("(conn=%p)", conn);
00388 if (!conn) return NULL;
00389
00390 rs = dui_odbc_recordset_new (conn);
00391 if (!rs) return NULL;
00392
00393 rc = SQLTables (rs->sql_hstmt,NULL, 0, NULL, 0, NULL,0, NULL, 0);
00394
00395 if ((SQL_SUCCESS != rc) && (SQL_SUCCESS_WITH_INFO != rc))
00396 {
00397 PERR ("Can't perform query rc=%d", rc);
00398 PRINT_SQLERR (SQL_HANDLE_STMT, rs->sql_hstmt);
00399 dui_odbc_recordset_release (&rs->recset);
00400 return NULL;
00401 }
00402
00403 LEAVE ("(conn=%p)", conn);
00404
00405
00406 rs->ncols = -1;
00407 return &rs->recset;
00408 }
00409
00410
00411
00412
00413 DuiDBRecordSet *
00414 dui_odbc_connection_table_columns (DuiDBConnection *dbc,
00415 const gchar * tablename)
00416 {
00417 DuiODBCConnection *conn = (DuiODBCConnection *) dbc;
00418 DuiODBCRecordSet *rs;
00419 SQLRETURN rc;
00420
00421 ENTER ("(conn=%p, table=%s)", conn, tablename);
00422 if (!conn || !tablename) return NULL;
00423
00424 rs = dui_odbc_recordset_new (conn);
00425 if (!rs) return NULL;
00426
00427 rc=SQLColumns (rs->sql_hstmt,NULL, 0, NULL, 0,
00428 (guchar *) tablename, SQL_NTS, NULL, 0);
00429
00430 if ((SQL_SUCCESS != rc) && (SQL_SUCCESS_WITH_INFO != rc))
00431 {
00432 PERR ("Can't perform query rc=%d", rc);
00433 PRINT_SQLERR (SQL_HANDLE_STMT, rs->sql_hstmt);
00434 dui_odbc_recordset_release (&rs->recset);
00435 return NULL;
00436 }
00437
00438 LEAVE ("(conn=%p, table=%s)", conn, tablename);
00439
00440
00441 rs->ncols = -1;
00442 return &rs->recset;
00443 }
00444
00445
00446
00447
00448 static void
00449 dui_odbc_recordset_get_column_labels (DuiODBCRecordSet *rs)
00450 {
00451 SQLSMALLINT ncols;
00452 SQLRETURN rc;
00453 gint i;
00454
00455 if (0 <= rs->ncols) return;
00456
00457
00458
00459
00460
00461
00462 rc = SQLNumResultCols (rs->sql_hstmt, &ncols);
00463 if ((SQL_SUCCESS != rc) && (SQL_SUCCESS_WITH_INFO != rc))
00464 {
00465 PERR ("Can't get num columns rc=%d", rc);
00466 PRINT_SQLERR (SQL_HANDLE_STMT, rs->sql_hstmt);
00467 return;
00468 }
00469
00470 if (ncols > rs->arrsize)
00471 {
00472 PERR( "screwed not enough columns !! ");
00473 ncols = rs->arrsize;
00474 }
00475
00476 for (i=0; i<ncols; i++)
00477 {
00479 guchar namebuff[300];
00480 SQLSMALLINT namelen;
00481 SQLULEN column_size;
00482 SQLSMALLINT datatype;
00483 SQLSMALLINT decimal_digits;
00484 SQLSMALLINT nullable;
00485
00486 rc = SQLDescribeCol (rs->sql_hstmt, i+1, namebuff, 299, &namelen,
00487 &datatype, &column_size, &decimal_digits, &nullable);
00488 if ((SQL_SUCCESS != rc) && (SQL_SUCCESS_WITH_INFO != rc))
00489 {
00490 PERR ("Can't describe col rc=%d", rc);
00491 PRINT_SQLERR (SQL_HANDLE_STMT, rs->sql_hstmt);
00492 return;
00493 }
00494
00495 namebuff[namelen] = 0x0;
00496 PINFO ("column %d has name\'%s\'", i, namebuff);
00497
00498 g_free (rs->column_labels[i]);
00499 rs->column_labels[i] = g_strdup ((gchar*)namebuff);
00500 rs->column_datatype[i] = datatype;
00501 }
00502
00503 rs->ncols = ncols;
00504 }
00505
00506
00507
00508 static int
00509 get_col_by_name (DuiODBCRecordSet *rs, const gchar * fieldname)
00510 {
00511 gint i;
00512 const gchar * fp;
00513
00514
00515 for (i=0; i<rs->ncols; i++)
00516 {
00517 if (!strcasecmp (fieldname, rs->column_labels[i])) return i;
00518 }
00519
00520
00521 fp = strrchr (fieldname, '.');
00522 if (!fp) return -1;
00523 fp ++;
00524
00525 for (i=0; i<rs->ncols; i++)
00526 {
00527 if (!strcasecmp (fp, rs->column_labels[i])) return i;
00528 }
00529
00530 return -1;
00531 }
00532
00533
00534
00535 static gint
00536 dui_odbc_recordset_rewind (DuiDBRecordSet *recset)
00537 {
00539
00540
00541 return dui_odbc_recordset_fetch_row (recset);
00542 }
00543
00544
00545
00546 gint
00547 dui_odbc_recordset_fetch_row (DuiDBRecordSet *recset)
00548 {
00549 DuiODBCRecordSet *rs = (DuiODBCRecordSet *) recset;
00550 SQLRETURN rc;
00551
00552 g_return_val_if_fail (rs, 0);
00553
00554 rc = SQLFetch(rs->sql_hstmt);
00555
00556
00557 if (SQL_NO_DATA == rc) return 0;
00558 if (SQL_NULL_DATA == rc) return 0;
00559
00560 if ((SQL_SUCCESS != rc) && (SQL_SUCCESS_WITH_INFO != rc))
00561 {
00562 PERR ("Can't fetch row rc=%d", rc);
00563 PRINT_SQLERR (SQL_HANDLE_STMT, rs->sql_hstmt);
00564 return 0;
00565 }
00566
00567 return 1;
00568 }
00569
00570
00571
00572 const gchar *
00573 dui_odbc_recordset_get_value (DuiDBRecordSet *recset, const gchar * fieldname)
00574 {
00575 DuiODBCRecordSet *rs = (DuiODBCRecordSet *) recset;
00576 gint column;
00577
00578 g_return_val_if_fail (rs, NULL);
00579
00580
00581
00582
00583
00584 if (0 > rs->ncols)
00585 {
00586 dui_odbc_recordset_get_column_labels (rs);
00587 }
00588
00589 column = get_col_by_name (rs, fieldname);
00590 if (0 > column) return NULL;
00591
00592 LEAVE ("(rs=%p, fieldname=%s) {val=\'%s\'}", rs, fieldname, rs->values[column]);
00593 return rs->values[column];
00594 }
00595
00596
00597
00598 static void
00599 dui_odbc_plugin_free (DuiDBPlugin *plg)
00600 {
00601 g_free (plg);
00602 }
00603
00604
00605
00606 static DuiDBPlugin *
00607 dui_odbc_plugin_new (void)
00608 {
00609 DuiDBPlugin *plg;
00610 plg = g_new0 (DuiDBPlugin, 1);
00611 plg->db_provider_name = "odbc";
00612 plg->plugin_free = dui_odbc_plugin_free;
00613 plg->connection_new = dui_odbc_connection_new;
00614 plg->connection_free = dui_odbc_connection_free;
00615 plg->connection_exec = dui_odbc_connection_exec;
00616 plg->connection_tables = dui_odbc_connection_tables;
00617 plg->connection_table_columns = dui_odbc_connection_table_columns;
00618 plg->recordset_free = dui_odbc_recordset_release;
00619 plg->recordset_rewind = dui_odbc_recordset_rewind;
00620 plg->recordset_fetch_row = dui_odbc_recordset_fetch_row;
00621 plg->recordset_get_value = dui_odbc_recordset_get_value;
00622 plg->recordset_get_error = NULL;
00623
00624 return plg;
00625 }
00626
00627 #endif
00628
00629
00630 void
00631 dui_odbc_init (void)
00632 {
00633 #ifdef USE_ODBC
00634 DuiDBPlugin *plg;
00635 plg = dui_odbc_plugin_new();
00636 dui_db_provider_register (plg);
00637 #else
00638
00639 PERR ("The DWI db drivers were compiled without ODBC support");
00640 #endif
00641 }
00642
00645
00646