1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/glpsql.c Mon Dec 06 13:09:21 2010 +0100
1.3 @@ -0,0 +1,1627 @@
1.4 +/* glpsql.c */
1.5 +
1.6 +/***********************************************************************
1.7 +* This code is part of GLPK (GNU Linear Programming Kit).
1.8 +*
1.9 +* Author: Heinrich Schuchardt <xypron.glpk@gmx.de>.
1.10 +*
1.11 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
1.12 +* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
1.13 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
1.14 +* E-mail: <mao@gnu.org>.
1.15 +*
1.16 +* GLPK is free software: you can redistribute it and/or modify it
1.17 +* under the terms of the GNU General Public License as published by
1.18 +* the Free Software Foundation, either version 3 of the License, or
1.19 +* (at your option) any later version.
1.20 +*
1.21 +* GLPK is distributed in the hope that it will be useful, but WITHOUT
1.22 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1.23 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
1.24 +* License for more details.
1.25 +*
1.26 +* You should have received a copy of the GNU General Public License
1.27 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
1.28 +***********************************************************************/
1.29 +
1.30 +#ifdef HAVE_CONFIG_H
1.31 +#include <config.h>
1.32 +#endif
1.33 +
1.34 +#include "glpmpl.h"
1.35 +#include "glpsql.h"
1.36 +
1.37 +#ifdef ODBC_DLNAME
1.38 +#define HAVE_ODBC
1.39 +#define libodbc ODBC_DLNAME
1.40 +#define h_odbc (get_env_ptr()->h_odbc)
1.41 +#endif
1.42 +
1.43 +#ifdef MYSQL_DLNAME
1.44 +#define HAVE_MYSQL
1.45 +#define libmysql MYSQL_DLNAME
1.46 +#define h_mysql (get_env_ptr()->h_mysql)
1.47 +#endif
1.48 +
1.49 +static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
1.50 + **sqllines);
1.51 +static void *db_mysql_open_int(TABDCA *dca, int mode, const char
1.52 + **sqllines);
1.53 +
1.54 +/**********************************************************************/
1.55 +
1.56 +#if defined(HAVE_ODBC) || defined(HAVE_MYSQL)
1.57 +
1.58 +#define SQL_FIELD_MAX 100
1.59 +/* maximal field count */
1.60 +
1.61 +#define SQL_FDLEN_MAX 255
1.62 +/* maximal field length */
1.63 +
1.64 +/***********************************************************************
1.65 +* NAME
1.66 +*
1.67 +* args_concat - concatenate arguments
1.68 +*
1.69 +* SYNOPSIS
1.70 +*
1.71 +* static char **args_concat(TABDCA *dca);
1.72 +*
1.73 +* DESCRIPTION
1.74 +*
1.75 +* The arguments passed in dca are SQL statements. A SQL statement may
1.76 +* be split over multiple arguments. The last argument of a SQL
1.77 +* statement will be terminated with a semilocon. Each SQL statement is
1.78 +* merged into a single zero terminated string. Boundaries between
1.79 +* arguments are replaced by space.
1.80 +*
1.81 +* RETURNS
1.82 +*
1.83 +* Buffer with SQL statements */
1.84 +
1.85 +static char **args_concat(TABDCA *dca)
1.86 +{
1.87 + const char *arg;
1.88 + int i;
1.89 + int j;
1.90 + int j0;
1.91 + int j1;
1.92 + int len;
1.93 + int lentot;
1.94 + int narg;
1.95 + int nline = 0;
1.96 + void *ret;
1.97 + char **sqllines = NULL;
1.98 +
1.99 + narg = mpl_tab_num_args(dca);
1.100 + /* The SQL statements start with argument 3. */
1.101 + if (narg < 3)
1.102 + return NULL;
1.103 + /* Count the SQL statements */
1.104 + for (j = 3; j <= narg; j++)
1.105 + {
1.106 + arg = mpl_tab_get_arg(dca, j);
1.107 + len = strlen(arg);
1.108 + if (arg[len-1] == ';' || j == narg)
1.109 + nline ++;
1.110 + }
1.111 + /* Allocate string buffer. */
1.112 + sqllines = (char **) xmalloc((nline+1) * sizeof(char **));
1.113 + /* Join arguments */
1.114 + sqllines[0] = NULL;
1.115 + j0 = 3;
1.116 + i = 0;
1.117 + lentot = 0;
1.118 + for (j = 3; j <= narg; j++)
1.119 + {
1.120 + arg = mpl_tab_get_arg(dca, j);
1.121 + len = strlen(arg);
1.122 + lentot += len;
1.123 + if (arg[len-1] == ';' || j == narg)
1.124 + { /* Join arguments for a single SQL statement */
1.125 + sqllines[i] = xmalloc(lentot+1);
1.126 + sqllines[i+1] = NULL;
1.127 + sqllines[i][0] = 0x00;
1.128 + for (j1 = j0; j1 <= j; j1++)
1.129 + { if(j1>j0)
1.130 + strcat(sqllines[i], " ");
1.131 + strcat(sqllines[i], mpl_tab_get_arg(dca, j1));
1.132 + }
1.133 + len = strlen(sqllines[i]);
1.134 + if (sqllines[i][len-1] == ';')
1.135 + sqllines[i][len-1] = 0x00;
1.136 + j0 = j+1;
1.137 + i++;
1.138 + lentot = 0;
1.139 + }
1.140 + }
1.141 + return sqllines;
1.142 +}
1.143 +
1.144 +/***********************************************************************
1.145 +* NAME
1.146 +*
1.147 +* free_buffer - free multiline string buffer
1.148 +*
1.149 +* SYNOPSIS
1.150 +*
1.151 +* static void free_buffer(char **buf);
1.152 +*
1.153 +* DESCRIPTION
1.154 +*
1.155 +* buf is a list of strings terminated by NULL.
1.156 +* The memory for the strings and for the list is released. */
1.157 +
1.158 +static void free_buffer(char **buf)
1.159 +{ int i;
1.160 +
1.161 + for(i = 0; buf[i] != NULL; i++)
1.162 + xfree(buf[i]);
1.163 + xfree(buf);
1.164 +}
1.165 +
1.166 +static int db_escaped_string_length(const char* from)
1.167 +/* length of escaped string */
1.168 +{
1.169 + int count;
1.170 + const char *pointer;
1.171 +
1.172 + for (pointer = from, count = 0; *pointer != (char) '\0'; pointer++,
1.173 + count++)
1.174 + {
1.175 + switch (*pointer)
1.176 + {
1.177 + case '\'':
1.178 + count++;
1.179 + break;
1.180 + }
1.181 + }
1.182 +
1.183 + return count;
1.184 +}
1.185 +
1.186 +static int db_escape_string (char *to, const char *from)
1.187 +/* escape string*/
1.188 +{
1.189 + const char *source = from;
1.190 + char *target = to;
1.191 + unsigned int remaining;
1.192 +
1.193 + remaining = strlen(from);
1.194 +
1.195 + if (to == NULL)
1.196 + to = (char *) (from + remaining);
1.197 +
1.198 + while (remaining > 0)
1.199 + {
1.200 + switch (*source)
1.201 + {
1.202 + case '\'':
1.203 + *target = '\'';
1.204 + target++;
1.205 + *target = '\'';
1.206 + break;
1.207 +
1.208 + default:
1.209 + *target = *source;
1.210 + }
1.211 + source++;
1.212 + target++;
1.213 + remaining--;
1.214 + }
1.215 +
1.216 + /* Write the terminating NUL character. */
1.217 + *target = '\0';
1.218 +
1.219 + return target - to;
1.220 +}
1.221 +
1.222 +static char *db_generate_select_stmt(TABDCA *dca)
1.223 +/* generate select statement */
1.224 +{
1.225 + char *arg;
1.226 + char const *field;
1.227 + char *query;
1.228 + int j;
1.229 + int narg;
1.230 + int nf;
1.231 + int total;
1.232 +
1.233 + total = 50;
1.234 + nf = mpl_tab_num_flds(dca);
1.235 + narg = mpl_tab_num_args(dca);
1.236 + for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
1.237 + {
1.238 + field = mpl_tab_get_name(dca, j);
1.239 + total += strlen(field);
1.240 + total += 2;
1.241 + }
1.242 + arg = (char *) mpl_tab_get_arg(dca, narg);
1.243 + total += strlen(arg);
1.244 + query = xmalloc( total * sizeof(char));
1.245 + strcpy (query, "SELECT ");
1.246 + for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
1.247 + {
1.248 + field = mpl_tab_get_name(dca, j);
1.249 + strcat(query, field);
1.250 + if ( j < nf )
1.251 + strcat(query, ", ");
1.252 + }
1.253 + strcat(query, " FROM ");
1.254 + strcat(query, arg);
1.255 + return query;
1.256 +}
1.257 +
1.258 +static char *db_generate_insert_stmt(TABDCA *dca)
1.259 +/* generate insert statement */
1.260 +{
1.261 + char *arg;
1.262 + char const *field;
1.263 + char *query;
1.264 + int j;
1.265 + int narg;
1.266 + int nf;
1.267 + int total;
1.268 +
1.269 + total = 50;
1.270 + nf = mpl_tab_num_flds(dca);
1.271 + narg = mpl_tab_num_args(dca);
1.272 + for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
1.273 + {
1.274 + field = mpl_tab_get_name(dca, j);
1.275 + total += strlen(field);
1.276 + total += 5;
1.277 + }
1.278 + arg = (char *) mpl_tab_get_arg(dca, narg);
1.279 + total += strlen(arg);
1.280 + query = xmalloc( (total+1) * sizeof(char));
1.281 + strcpy (query, "INSERT INTO ");
1.282 + strcat(query, arg);
1.283 + strcat(query, " ( ");
1.284 + for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
1.285 + {
1.286 + field = mpl_tab_get_name(dca, j);
1.287 + strcat(query, field);
1.288 + if ( j < nf )
1.289 + strcat(query, ", ");
1.290 + }
1.291 + strcat(query, " ) VALUES ( ");
1.292 + for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
1.293 + {
1.294 + strcat(query, "?");
1.295 + if ( j < nf )
1.296 + strcat(query, ", ");
1.297 + }
1.298 + strcat(query, " )");
1.299 + return query;
1.300 +}
1.301 +
1.302 +#endif
1.303 +
1.304 +/**********************************************************************/
1.305 +
1.306 +#ifndef HAVE_ODBC
1.307 +
1.308 +void *db_iodbc_open(TABDCA *dca, int mode)
1.309 +{ xassert(dca == dca);
1.310 + xassert(mode == mode);
1.311 + xprintf("iODBC table driver not supported\n");
1.312 + return NULL;
1.313 +}
1.314 +
1.315 +int db_iodbc_read(TABDCA *dca, void *link)
1.316 +{ xassert(dca != dca);
1.317 + xassert(link != link);
1.318 + return 0;
1.319 +}
1.320 +
1.321 +int db_iodbc_write(TABDCA *dca, void *link)
1.322 +{ xassert(dca != dca);
1.323 + xassert(link != link);
1.324 + return 0;
1.325 +}
1.326 +
1.327 +int db_iodbc_close(TABDCA *dca, void *link)
1.328 +{ xassert(dca != dca);
1.329 + xassert(link != link);
1.330 + return 0;
1.331 +}
1.332 +
1.333 +#else
1.334 +
1.335 +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
1.336 +#include <windows.h>
1.337 +#endif
1.338 +
1.339 +#include <sql.h>
1.340 +#include <sqlext.h>
1.341 +
1.342 +struct db_odbc
1.343 +{
1.344 + int mode; /*'R' = Read, 'W' = Write*/
1.345 + SQLHDBC hdbc; /*connection handle*/
1.346 + SQLHENV henv; /*environment handle*/
1.347 + SQLHSTMT hstmt; /*statement handle*/
1.348 + SQLSMALLINT nresultcols; /* columns in result*/
1.349 + SQLULEN collen[SQL_FIELD_MAX+1];
1.350 + SQLLEN outlen[SQL_FIELD_MAX+1];
1.351 + SQLSMALLINT coltype[SQL_FIELD_MAX+1];
1.352 + SQLCHAR data[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
1.353 + SQLCHAR colname[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
1.354 + int isnumeric[SQL_FIELD_MAX+1];
1.355 + int nf;
1.356 + /* number of fields in the csv file */
1.357 + int ref[1+SQL_FIELD_MAX];
1.358 + /* ref[k] = k', if k-th field of the csv file corresponds to
1.359 + k'-th field in the table statement; if ref[k] = 0, k-th field
1.360 + of the csv file is ignored */
1.361 + SQLCHAR *query;
1.362 + /* query generated by db_iodbc_open */
1.363 +};
1.364 +
1.365 +SQLRETURN SQL_API dl_SQLAllocHandle (
1.366 + SQLSMALLINT HandleType,
1.367 + SQLHANDLE InputHandle,
1.368 + SQLHANDLE *OutputHandle)
1.369 +{
1.370 + typedef SQLRETURN SQL_API ep_SQLAllocHandle(
1.371 + SQLSMALLINT HandleType,
1.372 + SQLHANDLE InputHandle,
1.373 + SQLHANDLE *OutputHandle);
1.374 +
1.375 + ep_SQLAllocHandle *fn;
1.376 + fn = (ep_SQLAllocHandle *) xdlsym(h_odbc, "SQLAllocHandle");
1.377 + xassert(fn != NULL);
1.378 + return (*fn)(HandleType, InputHandle, OutputHandle);
1.379 +}
1.380 +
1.381 +SQLRETURN SQL_API dl_SQLBindCol (
1.382 + SQLHSTMT StatementHandle,
1.383 + SQLUSMALLINT ColumnNumber,
1.384 + SQLSMALLINT TargetType,
1.385 + SQLPOINTER TargetValue,
1.386 + SQLLEN BufferLength,
1.387 + SQLLEN *StrLen_or_Ind)
1.388 +{
1.389 + typedef SQLRETURN SQL_API ep_SQLBindCol(
1.390 + SQLHSTMT StatementHandle,
1.391 + SQLUSMALLINT ColumnNumber,
1.392 + SQLSMALLINT TargetType,
1.393 + SQLPOINTER TargetValue,
1.394 + SQLLEN BufferLength,
1.395 + SQLLEN *StrLen_or_Ind);
1.396 + ep_SQLBindCol *fn;
1.397 + fn = (ep_SQLBindCol *) xdlsym(h_odbc, "SQLBindCol");
1.398 + xassert(fn != NULL);
1.399 + return (*fn)(StatementHandle, ColumnNumber, TargetType,
1.400 + TargetValue, BufferLength, StrLen_or_Ind);
1.401 +}
1.402 +
1.403 +SQLRETURN SQL_API dl_SQLCloseCursor (
1.404 + SQLHSTMT StatementHandle)
1.405 +{
1.406 + typedef SQLRETURN SQL_API ep_SQLCloseCursor (
1.407 + SQLHSTMT StatementHandle);
1.408 +
1.409 + ep_SQLCloseCursor *fn;
1.410 + fn = (ep_SQLCloseCursor *) xdlsym(h_odbc, "SQLCloseCursor");
1.411 + xassert(fn != NULL);
1.412 + return (*fn)(StatementHandle);
1.413 +}
1.414 +
1.415 +
1.416 +SQLRETURN SQL_API dl_SQLDisconnect (
1.417 + SQLHDBC ConnectionHandle)
1.418 +{
1.419 + typedef SQLRETURN SQL_API ep_SQLDisconnect(
1.420 + SQLHDBC ConnectionHandle);
1.421 +
1.422 + ep_SQLDisconnect *fn;
1.423 + fn = (ep_SQLDisconnect *) xdlsym(h_odbc, "SQLDisconnect");
1.424 + xassert(fn != NULL);
1.425 + return (*fn)(ConnectionHandle);
1.426 +}
1.427 +
1.428 +SQLRETURN SQL_API dl_SQLDriverConnect (
1.429 + SQLHDBC hdbc,
1.430 + SQLHWND hwnd,
1.431 + SQLCHAR *szConnStrIn,
1.432 + SQLSMALLINT cbConnStrIn,
1.433 + SQLCHAR *szConnStrOut,
1.434 + SQLSMALLINT cbConnStrOutMax,
1.435 + SQLSMALLINT *pcbConnStrOut,
1.436 + SQLUSMALLINT fDriverCompletion)
1.437 +{
1.438 + typedef SQLRETURN SQL_API ep_SQLDriverConnect(
1.439 + SQLHDBC hdbc,
1.440 + SQLHWND hwnd,
1.441 + SQLCHAR * szConnStrIn,
1.442 + SQLSMALLINT cbConnStrIn,
1.443 + SQLCHAR * szConnStrOut,
1.444 + SQLSMALLINT cbConnStrOutMax,
1.445 + SQLSMALLINT * pcbConnStrOut,
1.446 + SQLUSMALLINT fDriverCompletion);
1.447 +
1.448 + ep_SQLDriverConnect *fn;
1.449 + fn = (ep_SQLDriverConnect *) xdlsym(h_odbc, "SQLDriverConnect");
1.450 + xassert(fn != NULL);
1.451 + return (*fn)(hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut,
1.452 + cbConnStrOutMax, pcbConnStrOut, fDriverCompletion);
1.453 +}
1.454 +
1.455 +SQLRETURN SQL_API dl_SQLEndTran (
1.456 + SQLSMALLINT HandleType,
1.457 + SQLHANDLE Handle,
1.458 + SQLSMALLINT CompletionType)
1.459 +{
1.460 + typedef SQLRETURN SQL_API ep_SQLEndTran (
1.461 + SQLSMALLINT HandleType,
1.462 + SQLHANDLE Handle,
1.463 + SQLSMALLINT CompletionType);
1.464 +
1.465 + ep_SQLEndTran *fn;
1.466 + fn = (ep_SQLEndTran *) xdlsym(h_odbc, "SQLEndTran");
1.467 + xassert(fn != NULL);
1.468 + return (*fn)(HandleType, Handle, CompletionType);
1.469 +}
1.470 +
1.471 +SQLRETURN SQL_API dl_SQLExecDirect (
1.472 + SQLHSTMT StatementHandle,
1.473 + SQLCHAR * StatementText,
1.474 + SQLINTEGER TextLength)
1.475 +{
1.476 + typedef SQLRETURN SQL_API ep_SQLExecDirect (
1.477 + SQLHSTMT StatementHandle,
1.478 + SQLCHAR * StatementText,
1.479 + SQLINTEGER TextLength);
1.480 +
1.481 + ep_SQLExecDirect *fn;
1.482 + fn = (ep_SQLExecDirect *) xdlsym(h_odbc, "SQLExecDirect");
1.483 + xassert(fn != NULL);
1.484 + return (*fn)(StatementHandle, StatementText, TextLength);
1.485 +}
1.486 +
1.487 +SQLRETURN SQL_API dl_SQLFetch (
1.488 + SQLHSTMT StatementHandle)
1.489 +{
1.490 + typedef SQLRETURN SQL_API ep_SQLFetch (
1.491 + SQLHSTMT StatementHandle);
1.492 +
1.493 + ep_SQLFetch *fn;
1.494 + fn = (ep_SQLFetch*) xdlsym(h_odbc, "SQLFetch");
1.495 + xassert(fn != NULL);
1.496 + return (*fn)(StatementHandle);
1.497 +}
1.498 +
1.499 +SQLRETURN SQL_API dl_SQLFreeHandle (
1.500 + SQLSMALLINT HandleType,
1.501 + SQLHANDLE Handle)
1.502 +{
1.503 + typedef SQLRETURN SQL_API ep_SQLFreeHandle (
1.504 + SQLSMALLINT HandleType,
1.505 + SQLHANDLE Handle);
1.506 +
1.507 + ep_SQLFreeHandle *fn;
1.508 + fn = (ep_SQLFreeHandle *) xdlsym(h_odbc, "SQLFreeHandle");
1.509 + xassert(fn != NULL);
1.510 + return (*fn)(HandleType, Handle);
1.511 +}
1.512 +
1.513 +SQLRETURN SQL_API dl_SQLDescribeCol (
1.514 + SQLHSTMT StatementHandle,
1.515 + SQLUSMALLINT ColumnNumber,
1.516 + SQLCHAR * ColumnName,
1.517 + SQLSMALLINT BufferLength,
1.518 + SQLSMALLINT * NameLength,
1.519 + SQLSMALLINT * DataType,
1.520 + SQLULEN * ColumnSize,
1.521 + SQLSMALLINT * DecimalDigits,
1.522 + SQLSMALLINT * Nullable)
1.523 +{
1.524 + typedef SQLRETURN SQL_API ep_SQLDescribeCol (
1.525 + SQLHSTMT StatementHandle,
1.526 + SQLUSMALLINT ColumnNumber,
1.527 + SQLCHAR *ColumnName,
1.528 + SQLSMALLINT BufferLength,
1.529 + SQLSMALLINT *NameLength,
1.530 + SQLSMALLINT *DataType,
1.531 + SQLULEN *ColumnSize,
1.532 + SQLSMALLINT *DecimalDigits,
1.533 + SQLSMALLINT *Nullable);
1.534 +
1.535 + ep_SQLDescribeCol *fn;
1.536 + fn = (ep_SQLDescribeCol *) xdlsym(h_odbc, "SQLDescribeCol");
1.537 + xassert(fn != NULL);
1.538 + return (*fn)(StatementHandle, ColumnNumber, ColumnName,
1.539 + BufferLength, NameLength,
1.540 + DataType, ColumnSize, DecimalDigits, Nullable);
1.541 +}
1.542 +
1.543 +SQLRETURN SQL_API dl_SQLGetDiagRec (
1.544 + SQLSMALLINT HandleType,
1.545 + SQLHANDLE Handle,
1.546 + SQLSMALLINT RecNumber,
1.547 + SQLCHAR *Sqlstate,
1.548 + SQLINTEGER *NativeError,
1.549 + SQLCHAR *MessageText,
1.550 + SQLSMALLINT BufferLength,
1.551 + SQLSMALLINT *TextLength)
1.552 +{
1.553 + typedef SQLRETURN SQL_API ep_SQLGetDiagRec (
1.554 + SQLSMALLINT HandleType,
1.555 + SQLHANDLE Handle,
1.556 + SQLSMALLINT RecNumber,
1.557 + SQLCHAR *Sqlstate,
1.558 + SQLINTEGER *NativeError,
1.559 + SQLCHAR *MessageText,
1.560 + SQLSMALLINT BufferLength,
1.561 + SQLSMALLINT *TextLength);
1.562 +
1.563 + ep_SQLGetDiagRec *fn;
1.564 + fn = (ep_SQLGetDiagRec *) xdlsym(h_odbc, "SQLGetDiagRec");
1.565 + xassert(fn != NULL);
1.566 + return (*fn)(HandleType, Handle, RecNumber, Sqlstate,
1.567 + NativeError, MessageText, BufferLength, TextLength);
1.568 +}
1.569 +
1.570 +SQLRETURN SQL_API dl_SQLGetInfo (
1.571 + SQLHDBC ConnectionHandle,
1.572 + SQLUSMALLINT InfoType,
1.573 + SQLPOINTER InfoValue,
1.574 + SQLSMALLINT BufferLength,
1.575 + SQLSMALLINT *StringLength)
1.576 +{
1.577 + typedef SQLRETURN SQL_API ep_SQLGetInfo (
1.578 + SQLHDBC ConnectionHandle,
1.579 + SQLUSMALLINT InfoType,
1.580 + SQLPOINTER InfoValue,
1.581 + SQLSMALLINT BufferLength,
1.582 + SQLSMALLINT *StringLength);
1.583 +
1.584 + ep_SQLGetInfo *fn;
1.585 + fn = (ep_SQLGetInfo *) xdlsym(h_odbc, "SQLGetInfo");
1.586 + xassert(fn != NULL);
1.587 + return (*fn)(ConnectionHandle, InfoType, InfoValue, BufferLength,
1.588 + StringLength);
1.589 +}
1.590 +
1.591 +SQLRETURN SQL_API dl_SQLNumResultCols (
1.592 + SQLHSTMT StatementHandle,
1.593 + SQLSMALLINT *ColumnCount)
1.594 +{
1.595 + typedef SQLRETURN SQL_API ep_SQLNumResultCols (
1.596 + SQLHSTMT StatementHandle,
1.597 + SQLSMALLINT *ColumnCount);
1.598 +
1.599 + ep_SQLNumResultCols *fn;
1.600 + fn = (ep_SQLNumResultCols *) xdlsym(h_odbc, "SQLNumResultCols");
1.601 + xassert(fn != NULL);
1.602 + return (*fn)(StatementHandle, ColumnCount);
1.603 +}
1.604 +
1.605 +SQLRETURN SQL_API dl_SQLSetConnectAttr (
1.606 + SQLHDBC ConnectionHandle,
1.607 + SQLINTEGER Attribute,
1.608 + SQLPOINTER Value,
1.609 + SQLINTEGER StringLength)
1.610 +{
1.611 + typedef SQLRETURN SQL_API ep_SQLSetConnectAttr (
1.612 + SQLHDBC ConnectionHandle,
1.613 + SQLINTEGER Attribute,
1.614 + SQLPOINTER Value,
1.615 + SQLINTEGER StringLength);
1.616 +
1.617 + ep_SQLSetConnectAttr *fn;
1.618 + fn = (ep_SQLSetConnectAttr *) xdlsym(h_odbc, "SQLSetConnectAttr");
1.619 + xassert(fn != NULL);
1.620 + return (*fn)(ConnectionHandle, Attribute, Value, StringLength);
1.621 +}
1.622 +
1.623 +SQLRETURN SQL_API dl_SQLSetEnvAttr (
1.624 + SQLHENV EnvironmentHandle,
1.625 + SQLINTEGER Attribute,
1.626 + SQLPOINTER Value,
1.627 + SQLINTEGER StringLength)
1.628 +{
1.629 + typedef SQLRETURN SQL_API ep_SQLSetEnvAttr (
1.630 + SQLHENV EnvironmentHandle,
1.631 + SQLINTEGER Attribute,
1.632 + SQLPOINTER Value,
1.633 + SQLINTEGER StringLength);
1.634 +
1.635 + ep_SQLSetEnvAttr *fn;
1.636 + fn = (ep_SQLSetEnvAttr *) xdlsym(h_odbc, "SQLSetEnvAttr");
1.637 + xassert(fn != NULL);
1.638 + return (*fn)(EnvironmentHandle, Attribute, Value, StringLength);
1.639 +}
1.640 +
1.641 +static void extract_error(
1.642 + char *fn,
1.643 + SQLHANDLE handle,
1.644 + SQLSMALLINT type);
1.645 +
1.646 +static int is_numeric(
1.647 + SQLSMALLINT coltype);
1.648 +
1.649 +/***********************************************************************
1.650 +* NAME
1.651 +*
1.652 +* db_iodbc_open - open connection to ODBC data base
1.653 +*
1.654 +* SYNOPSIS
1.655 +*
1.656 +* #include "glpsql.h"
1.657 +* void *db_iodbc_open(TABDCA *dca, int mode);
1.658 +*
1.659 +* DESCRIPTION
1.660 +*
1.661 +* The routine db_iodbc_open opens a connection to an ODBC data base.
1.662 +* It then executes the sql statements passed.
1.663 +*
1.664 +* In the case of table read the SELECT statement is executed.
1.665 +*
1.666 +* In the case of table write the INSERT statement is prepared.
1.667 +* RETURNS
1.668 +*
1.669 +* The routine returns a pointer to data storage area created. */
1.670 +void *db_iodbc_open(TABDCA *dca, int mode)
1.671 +{ void *ret;
1.672 + char **sqllines;
1.673 +
1.674 + sqllines = args_concat(dca);
1.675 + if (sqllines == NULL)
1.676 + { xprintf("Missing arguments in table statement.\n"
1.677 + "Please, supply table driver, dsn, and query.\n");
1.678 + return NULL;
1.679 + }
1.680 + ret = db_iodbc_open_int(dca, mode, (const char **) sqllines);
1.681 + free_buffer(sqllines);
1.682 + return ret;
1.683 +}
1.684 +
1.685 +static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
1.686 + **sqllines)
1.687 +{
1.688 + struct db_odbc *sql;
1.689 + SQLRETURN ret;
1.690 + SQLCHAR FAR *dsn;
1.691 + SQLCHAR info[256];
1.692 + SQLSMALLINT colnamelen;
1.693 + SQLSMALLINT nullable;
1.694 + SQLSMALLINT scale;
1.695 + const char *arg;
1.696 + int narg;
1.697 + int i, j;
1.698 + int total;
1.699 +
1.700 + if (libodbc == NULL)
1.701 + {
1.702 + xprintf("No loader for shared ODBC library available\n");
1.703 + return NULL;
1.704 + }
1.705 +
1.706 + if (h_odbc == NULL)
1.707 + {
1.708 + h_odbc = xdlopen(libodbc);
1.709 + if (h_odbc == NULL)
1.710 + { xprintf("unable to open library %s\n", libodbc);
1.711 + xprintf("%s\n", xerrmsg());
1.712 + return NULL;
1.713 + }
1.714 + }
1.715 +
1.716 + sql = (struct db_odbc *) xmalloc(sizeof(struct db_odbc));
1.717 + if (sql == NULL)
1.718 + return NULL;
1.719 +
1.720 + sql->mode = mode;
1.721 + sql->hdbc = NULL;
1.722 + sql->henv = NULL;
1.723 + sql->hstmt = NULL;
1.724 + sql->query = NULL;
1.725 + narg = mpl_tab_num_args(dca);
1.726 +
1.727 + dsn = (SQLCHAR FAR *) mpl_tab_get_arg(dca, 2);
1.728 + /* allocate an environment handle */
1.729 + ret = dl_SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
1.730 + &(sql->henv));
1.731 + /* set attribute to enable application to run as ODBC 3.0
1.732 + application */
1.733 + ret = dl_SQLSetEnvAttr(sql->henv, SQL_ATTR_ODBC_VERSION,
1.734 + (void *) SQL_OV_ODBC3, 0);
1.735 + /* allocate a connection handle */
1.736 + ret = dl_SQLAllocHandle(SQL_HANDLE_DBC, sql->henv, &(sql->hdbc));
1.737 + /* connect */
1.738 + ret = dl_SQLDriverConnect(sql->hdbc, NULL, dsn, SQL_NTS, NULL, 0,
1.739 + NULL, SQL_DRIVER_COMPLETE);
1.740 + if (SQL_SUCCEEDED(ret))
1.741 + { /* output information about data base connection */
1.742 + xprintf("Connected to ");
1.743 + dl_SQLGetInfo(sql->hdbc, SQL_DBMS_NAME, (SQLPOINTER)info,
1.744 + sizeof(info), NULL);
1.745 + xprintf("%s ", info);
1.746 + dl_SQLGetInfo(sql->hdbc, SQL_DBMS_VER, (SQLPOINTER)info,
1.747 + sizeof(info), NULL);
1.748 + xprintf("%s - ", info);
1.749 + dl_SQLGetInfo(sql->hdbc, SQL_DATABASE_NAME, (SQLPOINTER)info,
1.750 + sizeof(info), NULL);
1.751 + xprintf("%s\n", info);
1.752 + }
1.753 + else
1.754 + { /* describe error */
1.755 + xprintf("Failed to connect\n");
1.756 + extract_error("SQLDriverConnect", sql->hdbc, SQL_HANDLE_DBC);
1.757 + dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
1.758 + dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
1.759 + xfree(sql);
1.760 + return NULL;
1.761 + }
1.762 + /* set AUTOCOMMIT on*/
1.763 + ret = dl_SQLSetConnectAttr(sql->hdbc, SQL_ATTR_AUTOCOMMIT,
1.764 + (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0);
1.765 + /* allocate a statement handle */
1.766 + ret = dl_SQLAllocHandle(SQL_HANDLE_STMT, sql->hdbc, &(sql->hstmt));
1.767 +
1.768 + /* initialization queries */
1.769 + for(j = 0; sqllines[j+1] != NULL; j++)
1.770 + {
1.771 + sql->query = (SQLCHAR *) sqllines[j];
1.772 + xprintf("%s\n", sql->query);
1.773 + ret = dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS);
1.774 + switch (ret)
1.775 + {
1.776 + case SQL_SUCCESS:
1.777 + case SQL_SUCCESS_WITH_INFO:
1.778 + case SQL_NO_DATA_FOUND:
1.779 + break;
1.780 + default:
1.781 + xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n",
1.782 + sql->query);
1.783 + extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
1.784 + dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
1.785 + dl_SQLDisconnect(sql->hdbc);
1.786 + dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
1.787 + dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
1.788 + xfree(sql);
1.789 + return NULL;
1.790 + }
1.791 + /* commit statement */
1.792 + dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
1.793 + }
1.794 +
1.795 + if ( sql->mode == 'R' )
1.796 + { sql->nf = mpl_tab_num_flds(dca);
1.797 + for(j = 0; sqllines[j] != NULL; j++)
1.798 + arg = sqllines[j];
1.799 + total = strlen(arg);
1.800 + if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
1.801 + {
1.802 + total = strlen(arg);
1.803 + sql->query = xmalloc( (total+1) * sizeof(char));
1.804 + strcpy (sql->query, arg);
1.805 + }
1.806 + else
1.807 + {
1.808 + sql->query = db_generate_select_stmt(dca);
1.809 + }
1.810 + xprintf("%s\n", sql->query);
1.811 + if (dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS) !=
1.812 + SQL_SUCCESS)
1.813 + {
1.814 + xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n", sql->query);
1.815 + extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
1.816 + dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
1.817 + dl_SQLDisconnect(sql->hdbc);
1.818 + dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
1.819 + dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
1.820 + xfree(sql->query);
1.821 + xfree(sql);
1.822 + return NULL;
1.823 + }
1.824 + xfree(sql->query);
1.825 + /* determine number of result columns */
1.826 + ret = dl_SQLNumResultCols(sql->hstmt, &sql->nresultcols);
1.827 + total = sql->nresultcols;
1.828 + if (total > SQL_FIELD_MAX)
1.829 + { xprintf("db_iodbc_open: Too many fields (> %d) in query.\n"
1.830 + "\"%s\"\n", SQL_FIELD_MAX, sql->query);
1.831 + dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
1.832 + dl_SQLDisconnect(sql->hdbc);
1.833 + dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
1.834 + dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
1.835 + xfree(sql->query);
1.836 + return NULL;
1.837 + }
1.838 + for (i = 1; i <= total; i++)
1.839 + { /* return a set of attributes for a column */
1.840 + ret = dl_SQLDescribeCol(sql->hstmt, (SQLSMALLINT) i,
1.841 + sql->colname[i], SQL_FDLEN_MAX,
1.842 + &colnamelen, &(sql->coltype[i]), &(sql->collen[i]), &scale,
1.843 + &nullable);
1.844 + sql->isnumeric[i] = is_numeric(sql->coltype[i]);
1.845 + /* bind columns to program vars, converting all types to CHAR*/
1.846 + dl_SQLBindCol(sql->hstmt, i, SQL_CHAR, sql->data[i],
1.847 + SQL_FDLEN_MAX, &(sql->outlen[i]));
1.848 + for (j = sql->nf; j >= 1; j--)
1.849 + { if (strcmp(mpl_tab_get_name(dca, j), sql->colname[i]) == 0)
1.850 + break;
1.851 + }
1.852 + sql->ref[i] = j;
1.853 + }
1.854 + }
1.855 + else if ( sql->mode == 'W' )
1.856 + { for(j = 0; sqllines[j] != NULL; j++)
1.857 + arg = sqllines[j];
1.858 + if ( NULL != strchr(arg, '?') )
1.859 + {
1.860 + total = strlen(arg);
1.861 + sql->query = xmalloc( (total+1) * sizeof(char));
1.862 + strcpy (sql->query, arg);
1.863 + }
1.864 + else
1.865 + {
1.866 + sql->query = db_generate_insert_stmt(dca);
1.867 + }
1.868 + xprintf("%s\n", sql->query);
1.869 + }
1.870 + return sql;
1.871 +}
1.872 +
1.873 +int db_iodbc_read(TABDCA *dca, void *link)
1.874 +{
1.875 + struct db_odbc *sql;
1.876 + SQLRETURN ret;
1.877 + char buf[SQL_FDLEN_MAX+1];
1.878 + int i;
1.879 + int len;
1.880 + double num;
1.881 +
1.882 + sql = (struct db_odbc *) link;
1.883 +
1.884 + xassert(sql != NULL);
1.885 + xassert(sql->mode == 'R');
1.886 +
1.887 + ret=dl_SQLFetch(sql->hstmt);
1.888 + if (ret== SQL_ERROR)
1.889 + return -1;
1.890 + if (ret== SQL_NO_DATA_FOUND)
1.891 + return -1; /*EOF*/
1.892 + for (i=1; i <= sql->nresultcols; i++)
1.893 + {
1.894 + if (sql->ref[i] > 0)
1.895 + {
1.896 + len = sql->outlen[i];
1.897 + if (len != SQL_NULL_DATA)
1.898 + {
1.899 + if (len > SQL_FDLEN_MAX)
1.900 + len = SQL_FDLEN_MAX;
1.901 + else if (len < 0)
1.902 + len = 0;
1.903 + strncpy(buf, (const char *) sql->data[i], len);
1.904 + buf[len] = 0x00;
1.905 + if (0 != (sql->isnumeric[i]))
1.906 + { strspx(buf); /* remove spaces*/
1.907 + if (str2num(buf, &num) != 0)
1.908 + { xprintf("'%s' cannot be converted to a number.\n",
1.909 + buf);
1.910 + return 1;
1.911 + }
1.912 + mpl_tab_set_num(dca, sql->ref[i], num);
1.913 + }
1.914 + else
1.915 + { mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
1.916 + }
1.917 + }
1.918 + }
1.919 + }
1.920 + return 0;
1.921 +}
1.922 +
1.923 +int db_iodbc_write(TABDCA *dca, void *link)
1.924 +{
1.925 + struct db_odbc *sql;
1.926 + char *part;
1.927 + char *query;
1.928 + char *template;
1.929 + char num[50];
1.930 + int k;
1.931 + int len;
1.932 + int nf;
1.933 +
1.934 + sql = (struct db_odbc *) link;
1.935 + xassert(sql != NULL);
1.936 + xassert(sql->mode == 'W');
1.937 +
1.938 + len = strlen(sql->query);
1.939 + template = (char *) xmalloc( (len + 1) * sizeof(char) );
1.940 + strcpy(template, sql->query);
1.941 +
1.942 + nf = mpl_tab_num_flds(dca);
1.943 + for (k = 1; k <= nf; k++)
1.944 + { switch (mpl_tab_get_type(dca, k))
1.945 + { case 'N':
1.946 + len += 20;
1.947 + break;
1.948 + case 'S':
1.949 + len += db_escaped_string_length(mpl_tab_get_str(dca, k));
1.950 + len += 2;
1.951 + break;
1.952 + default:
1.953 + xassert(dca != dca);
1.954 + }
1.955 + }
1.956 + query = xmalloc( (len + 1 ) * sizeof(char) );
1.957 + query[0] = 0x00;
1.958 + for (k = 1, part = strtok (template, "?"); (part != NULL);
1.959 + part = strtok (NULL, "?"), k++)
1.960 + {
1.961 + if (k > nf) break;
1.962 + strcat( query, part );
1.963 + switch (mpl_tab_get_type(dca, k))
1.964 + { case 'N':
1.965 +#if 0 /* 02/XI-2010 by xypron */
1.966 + sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
1.967 +#else
1.968 + sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
1.969 +#endif
1.970 + strcat( query, num );
1.971 + break;
1.972 + case 'S':
1.973 + strcat( query, "'");
1.974 + db_escape_string( query + strlen(query),
1.975 + mpl_tab_get_str(dca, k) );
1.976 + strcat( query, "'");
1.977 + break;
1.978 + default:
1.979 + xassert(dca != dca);
1.980 + }
1.981 + }
1.982 + if (part != NULL)
1.983 + strcat(query, part);
1.984 + if (dl_SQLExecDirect(sql->hstmt, (SQLCHAR *) query, SQL_NTS)
1.985 + != SQL_SUCCESS)
1.986 + {
1.987 + xprintf("db_iodbc_write: Query\n\"%s\"\nfailed.\n", query);
1.988 + extract_error("SQLExecDirect", sql->hdbc, SQL_HANDLE_DBC);
1.989 + xfree(query);
1.990 + xfree(template);
1.991 + return 1;
1.992 + }
1.993 +
1.994 + xfree(query);
1.995 + xfree(template);
1.996 + return 0;
1.997 +}
1.998 +
1.999 +int db_iodbc_close(TABDCA *dca, void *link)
1.1000 +{
1.1001 + struct db_odbc *sql;
1.1002 +
1.1003 + sql = (struct db_odbc *) link;
1.1004 + xassert(sql != NULL);
1.1005 + /* Commit */
1.1006 + if ( sql->mode == 'W' )
1.1007 + dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
1.1008 + if ( sql->mode == 'R' )
1.1009 + dl_SQLCloseCursor(sql->hstmt);
1.1010 +
1.1011 + dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
1.1012 + dl_SQLDisconnect(sql->hdbc);
1.1013 + dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
1.1014 + dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
1.1015 + if ( sql->mode == 'W' )
1.1016 + xfree(sql->query);
1.1017 + xfree(sql);
1.1018 + dca->link = NULL;
1.1019 + return 0;
1.1020 +}
1.1021 +
1.1022 +static void extract_error(
1.1023 + char *fn,
1.1024 + SQLHANDLE handle,
1.1025 + SQLSMALLINT type)
1.1026 +{
1.1027 + SQLINTEGER i = 0;
1.1028 + SQLINTEGER native;
1.1029 + SQLCHAR state[ 7 ];
1.1030 + SQLCHAR text[256];
1.1031 + SQLSMALLINT len;
1.1032 + SQLRETURN ret;
1.1033 +
1.1034 + xprintf("\nThe driver reported the following diagnostics whilst "
1.1035 + "running %s\n", fn);
1.1036 +
1.1037 + do
1.1038 + {
1.1039 + ret = dl_SQLGetDiagRec(type, handle, ++i, state, &native, text,
1.1040 + sizeof(text), &len );
1.1041 + if (SQL_SUCCEEDED(ret))
1.1042 + xprintf("%s:%ld:%ld:%s\n", state, i, native, text);
1.1043 + }
1.1044 + while( ret == SQL_SUCCESS );
1.1045 +}
1.1046 +
1.1047 +static int is_numeric(SQLSMALLINT coltype)
1.1048 +{
1.1049 + int ret = 0;
1.1050 + switch (coltype)
1.1051 + {
1.1052 + case SQL_DECIMAL:
1.1053 + case SQL_NUMERIC:
1.1054 + case SQL_SMALLINT:
1.1055 + case SQL_INTEGER:
1.1056 + case SQL_REAL:
1.1057 + case SQL_FLOAT:
1.1058 + case SQL_DOUBLE:
1.1059 + case SQL_TINYINT:
1.1060 + case SQL_BIGINT:
1.1061 + ret = 1;
1.1062 + break;
1.1063 + }
1.1064 + return ret;
1.1065 +}
1.1066 +
1.1067 +#endif
1.1068 +
1.1069 +/**********************************************************************/
1.1070 +
1.1071 +#ifndef HAVE_MYSQL
1.1072 +
1.1073 +void *db_mysql_open(TABDCA *dca, int mode)
1.1074 +{ xassert(dca == dca);
1.1075 + xassert(mode == mode);
1.1076 + xprintf("MySQL table driver not supported\n");
1.1077 + return NULL;
1.1078 +}
1.1079 +
1.1080 +int db_mysql_read(TABDCA *dca, void *link)
1.1081 +{ xassert(dca != dca);
1.1082 + xassert(link != link);
1.1083 + return 0;
1.1084 +}
1.1085 +
1.1086 +int db_mysql_write(TABDCA *dca, void *link)
1.1087 +{ xassert(dca != dca);
1.1088 + xassert(link != link);
1.1089 + return 0;
1.1090 +}
1.1091 +
1.1092 +int db_mysql_close(TABDCA *dca, void *link)
1.1093 +{ xassert(dca != dca);
1.1094 + xassert(link != link);
1.1095 + return 0;
1.1096 +}
1.1097 +
1.1098 +#else
1.1099 +
1.1100 +#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
1.1101 +#include <windows.h>
1.1102 +#endif
1.1103 +
1.1104 +#ifdef __CYGWIN__
1.1105 +#define byte_defined 1
1.1106 +#endif
1.1107 +
1.1108 +#include <my_global.h>
1.1109 +#include <my_sys.h>
1.1110 +#include <mysql.h>
1.1111 +
1.1112 +struct db_mysql
1.1113 +{
1.1114 + int mode; /*'R' = Read, 'W' = Write*/
1.1115 + MYSQL *con; /*connection*/
1.1116 + MYSQL_RES *res; /*result*/
1.1117 + int nf;
1.1118 + /* number of fields in the csv file */
1.1119 + int ref[1+SQL_FIELD_MAX];
1.1120 + /* ref[k] = k', if k-th field of the csv file corresponds to
1.1121 + k'-th field in the table statement; if ref[k] = 0, k-th field
1.1122 + of the csv file is ignored */
1.1123 + char *query;
1.1124 + /* query generated by db_mysql_open */
1.1125 +};
1.1126 +
1.1127 +void STDCALL dl_mysql_close(MYSQL *sock)
1.1128 +{
1.1129 + typedef void STDCALL ep_mysql_close(MYSQL *sock);
1.1130 +
1.1131 + ep_mysql_close *fn;
1.1132 + fn = (ep_mysql_close *) xdlsym(h_mysql, "mysql_close");
1.1133 + xassert(fn != NULL);
1.1134 + return (*fn)(sock);
1.1135 +}
1.1136 +
1.1137 +const char * STDCALL dl_mysql_error(MYSQL *mysql)
1.1138 +{
1.1139 + typedef const char * STDCALL ep_mysql_error(MYSQL *mysql);
1.1140 +
1.1141 + ep_mysql_error *fn;
1.1142 + fn = (ep_mysql_error *) xdlsym(h_mysql, "mysql_error");
1.1143 + xassert(fn != NULL);
1.1144 + return (*fn)(mysql);
1.1145 +}
1.1146 +
1.1147 +MYSQL_FIELD * STDCALL dl_mysql_fetch_fields(MYSQL_RES *res)
1.1148 +{
1.1149 + typedef MYSQL_FIELD * STDCALL
1.1150 + ep_mysql_fetch_fields(MYSQL_RES *res);
1.1151 +
1.1152 + ep_mysql_fetch_fields *fn;
1.1153 + fn = (ep_mysql_fetch_fields *) xdlsym(h_mysql, "mysql_fetch_fields");
1.1154 + xassert(fn != NULL);
1.1155 + return (*fn)(res);
1.1156 +}
1.1157 +
1.1158 +unsigned long * STDCALL dl_mysql_fetch_lengths(MYSQL_RES *result)
1.1159 +{
1.1160 + typedef unsigned long * STDCALL
1.1161 + ep_mysql_fetch_lengths(MYSQL_RES *result);
1.1162 +
1.1163 + ep_mysql_fetch_lengths *fn;
1.1164 + fn = (ep_mysql_fetch_lengths *) xdlsym(h_mysql,
1.1165 + "mysql_fetch_lengths");
1.1166 + xassert(fn != NULL);
1.1167 + return (*fn)(result);
1.1168 +}
1.1169 +
1.1170 +MYSQL_ROW STDCALL dl_mysql_fetch_row(MYSQL_RES *result)
1.1171 +{
1.1172 + typedef MYSQL_ROW STDCALL ep_mysql_fetch_row(MYSQL_RES *result);
1.1173 +
1.1174 + ep_mysql_fetch_row *fn;
1.1175 + fn = (ep_mysql_fetch_row *) xdlsym(h_mysql, "mysql_fetch_row");
1.1176 + xassert(fn != NULL);
1.1177 + return (*fn)(result);
1.1178 +}
1.1179 +
1.1180 +unsigned int STDCALL dl_mysql_field_count(MYSQL *mysql)
1.1181 +{
1.1182 + typedef unsigned int STDCALL ep_mysql_field_count(MYSQL *mysql);
1.1183 +
1.1184 + ep_mysql_field_count *fn;
1.1185 + fn = (ep_mysql_field_count *) xdlsym(h_mysql, "mysql_field_count");
1.1186 + xassert(fn != NULL);
1.1187 + return (*fn)(mysql);
1.1188 +}
1.1189 +
1.1190 +MYSQL * STDCALL dl_mysql_init(MYSQL *mysql)
1.1191 +{
1.1192 + typedef MYSQL * STDCALL ep_mysql_init(MYSQL *mysql);
1.1193 +
1.1194 + ep_mysql_init *fn;
1.1195 + fn = (ep_mysql_init *) xdlsym(h_mysql, "mysql_init");
1.1196 + xassert(fn != NULL);
1.1197 + return (*fn)(mysql);
1.1198 +}
1.1199 +
1.1200 +unsigned int STDCALL dl_mysql_num_fields(MYSQL_RES *res)
1.1201 +{
1.1202 + typedef unsigned int STDCALL ep_mysql_num_fields(MYSQL_RES *res);
1.1203 +
1.1204 + ep_mysql_num_fields *fn;
1.1205 + fn = (ep_mysql_num_fields *) xdlsym(h_mysql, "mysql_num_fields");
1.1206 + xassert(fn != NULL);
1.1207 + return (*fn)(res);
1.1208 +}
1.1209 +
1.1210 +int STDCALL dl_mysql_query(MYSQL *mysql, const char *q)
1.1211 +{
1.1212 + typedef int STDCALL ep_mysql_query(MYSQL *mysql, const char *q);
1.1213 +
1.1214 + ep_mysql_query *fn;
1.1215 + fn = (ep_mysql_query *) xdlsym(h_mysql, "mysql_query");
1.1216 + xassert(fn != NULL);
1.1217 + return (*fn)(mysql, q);
1.1218 +}
1.1219 +
1.1220 +MYSQL * STDCALL dl_mysql_real_connect(MYSQL *mysql, const char *host,
1.1221 + const char *user,
1.1222 + const char *passwd,
1.1223 + const char *db,
1.1224 + unsigned int port,
1.1225 + const char *unix_socket,
1.1226 + unsigned long clientflag)
1.1227 +{
1.1228 + typedef MYSQL * STDCALL ep_mysql_real_connect(MYSQL *mysql,
1.1229 + const char *host,
1.1230 + const char *user,
1.1231 + const char *passwd,
1.1232 + const char *db,
1.1233 + unsigned int port,
1.1234 + const char *unix_socket,
1.1235 + unsigned long clientflag);
1.1236 +
1.1237 + ep_mysql_real_connect *fn;
1.1238 + fn = (ep_mysql_real_connect *) xdlsym(h_mysql,
1.1239 + "mysql_real_connect");
1.1240 + xassert(fn != NULL);
1.1241 + return (*fn)(mysql, host, user, passwd, db, port, unix_socket,
1.1242 + clientflag);
1.1243 +}
1.1244 +
1.1245 +MYSQL_RES * STDCALL dl_mysql_use_result(MYSQL *mysql)
1.1246 +{
1.1247 + typedef MYSQL_RES * STDCALL ep_mysql_use_result(MYSQL *mysql);
1.1248 + ep_mysql_use_result *fn;
1.1249 + fn = (ep_mysql_use_result *) xdlsym(h_mysql, "mysql_use_result");
1.1250 + xassert(fn != NULL);
1.1251 + return (*fn)(mysql);
1.1252 +}
1.1253 +
1.1254 +/***********************************************************************
1.1255 +* NAME
1.1256 +*
1.1257 +* db_mysql_open - open connection to ODBC data base
1.1258 +*
1.1259 +* SYNOPSIS
1.1260 +*
1.1261 +* #include "glpsql.h"
1.1262 +* void *db_mysql_open(TABDCA *dca, int mode);
1.1263 +*
1.1264 +* DESCRIPTION
1.1265 +*
1.1266 +* The routine db_mysql_open opens a connection to a MySQL data base.
1.1267 +* It then executes the sql statements passed.
1.1268 +*
1.1269 +* In the case of table read the SELECT statement is executed.
1.1270 +*
1.1271 +* In the case of table write the INSERT statement is prepared.
1.1272 +* RETURNS
1.1273 +*
1.1274 +* The routine returns a pointer to data storage area created. */
1.1275 +
1.1276 +void *db_mysql_open(TABDCA *dca, int mode)
1.1277 +{ void *ret;
1.1278 + char **sqllines;
1.1279 +
1.1280 + sqllines = args_concat(dca);
1.1281 + if (sqllines == NULL)
1.1282 + { xprintf("Missing arguments in table statement.\n"
1.1283 + "Please, supply table driver, dsn, and query.\n");
1.1284 + return NULL;
1.1285 + }
1.1286 + ret = db_mysql_open_int(dca, mode, (const char **) sqllines);
1.1287 + free_buffer(sqllines);
1.1288 + return ret;
1.1289 +}
1.1290 +
1.1291 +static void *db_mysql_open_int(TABDCA *dca, int mode, const char
1.1292 + **sqllines)
1.1293 +{
1.1294 + struct db_mysql *sql = NULL;
1.1295 + char *arg = NULL;
1.1296 + const char *field;
1.1297 + MYSQL_FIELD *fields;
1.1298 + char *keyword;
1.1299 + char *value;
1.1300 + char *query;
1.1301 + char *dsn;
1.1302 +/* "Server=[server_name];Database=[database_name];UID=[username];*/
1.1303 +/* PWD=[password];Port=[port]"*/
1.1304 + char *server = NULL; /* Server */
1.1305 + char *user = NULL; /* UID */
1.1306 + char *password = NULL; /* PWD */
1.1307 + char *database = NULL; /* Database */
1.1308 + unsigned int port = 0; /* Port */
1.1309 + int narg;
1.1310 + int i, j, total;
1.1311 +
1.1312 + if (libmysql == NULL)
1.1313 + {
1.1314 + xprintf("No loader for shared MySQL library available\n");
1.1315 + return NULL;
1.1316 + }
1.1317 +
1.1318 + if (h_mysql == NULL)
1.1319 + {
1.1320 + h_mysql = xdlopen(libmysql);
1.1321 + if (h_mysql == NULL)
1.1322 + { xprintf("unable to open library %s\n", libmysql);
1.1323 + xprintf("%s\n", xerrmsg());
1.1324 + return NULL;
1.1325 + }
1.1326 + }
1.1327 +
1.1328 + sql = (struct db_mysql *) xmalloc(sizeof(struct db_mysql));
1.1329 + if (sql == NULL)
1.1330 + return NULL;
1.1331 + sql->mode = mode;
1.1332 + sql->res = NULL;
1.1333 + sql->query = NULL;
1.1334 + sql->nf = mpl_tab_num_flds(dca);
1.1335 +
1.1336 + narg = mpl_tab_num_args(dca);
1.1337 + if (narg < 3 )
1.1338 + xprintf("MySQL driver: string list too short \n");
1.1339 +
1.1340 + /* get connection string*/
1.1341 + dsn = (char *) mpl_tab_get_arg(dca, 2);
1.1342 + /* copy connection string*/
1.1343 + i = strlen(dsn);
1.1344 + i++;
1.1345 + arg = xmalloc(i * sizeof(char));
1.1346 + strcpy(arg, dsn);
1.1347 + /*tokenize connection string*/
1.1348 + for (i = 1, keyword = strtok (arg, "="); (keyword != NULL);
1.1349 + keyword = strtok (NULL, "="), i++)
1.1350 + {
1.1351 + value = strtok (NULL, ";");
1.1352 + if (value==NULL)
1.1353 + {
1.1354 + xprintf("db_mysql_open: Missing value for keyword %s\n",
1.1355 + keyword);
1.1356 + xfree(arg);
1.1357 + xfree(sql);
1.1358 + return NULL;
1.1359 + }
1.1360 + if (0 == strcmp(keyword, "Server"))
1.1361 + server = value;
1.1362 + else if (0 == strcmp(keyword, "Database"))
1.1363 + database = value;
1.1364 + else if (0 == strcmp(keyword, "UID"))
1.1365 + user = value;
1.1366 + else if (0 == strcmp(keyword, "PWD"))
1.1367 + password = value;
1.1368 + else if (0 == strcmp(keyword, "Port"))
1.1369 + port = (unsigned int) atol(value);
1.1370 + }
1.1371 + /* Connect to database */
1.1372 + sql->con = dl_mysql_init(NULL);
1.1373 + if (!dl_mysql_real_connect(sql->con, server, user, password, database,
1.1374 + port, NULL, 0))
1.1375 + {
1.1376 + xprintf("db_mysql_open: Connect failed\n");
1.1377 + xprintf("%s\n", dl_mysql_error(sql->con));
1.1378 + xfree(arg);
1.1379 + xfree(sql);
1.1380 + return NULL;
1.1381 + }
1.1382 + xfree(arg);
1.1383 +
1.1384 + for(j = 0; sqllines[j+1] != NULL; j++)
1.1385 + { query = (char *) sqllines[j];
1.1386 + xprintf("%s\n", query);
1.1387 + if (dl_mysql_query(sql->con, query))
1.1388 + {
1.1389 + xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
1.1390 + xprintf("%s\n",dl_mysql_error(sql->con));
1.1391 + dl_mysql_close(sql->con);
1.1392 + xfree(sql);
1.1393 + return NULL;
1.1394 + }
1.1395 + }
1.1396 +
1.1397 + if ( sql->mode == 'R' )
1.1398 + { sql->nf = mpl_tab_num_flds(dca);
1.1399 + for(j = 0; sqllines[j] != NULL; j++)
1.1400 + arg = (char *) sqllines[j];
1.1401 + total = strlen(arg);
1.1402 + if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
1.1403 + {
1.1404 + total = strlen(arg);
1.1405 + query = xmalloc( (total+1) * sizeof(char));
1.1406 + strcpy (query, arg);
1.1407 + }
1.1408 + else
1.1409 + {
1.1410 + query = db_generate_select_stmt(dca);
1.1411 + }
1.1412 + xprintf("%s\n", query);
1.1413 + if (dl_mysql_query(sql->con, query))
1.1414 + {
1.1415 + xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
1.1416 + xprintf("%s\n",dl_mysql_error(sql->con));
1.1417 + dl_mysql_close(sql->con);
1.1418 + xfree(query);
1.1419 + xfree(sql);
1.1420 + return NULL;
1.1421 + }
1.1422 + xfree(query);
1.1423 + sql->res = dl_mysql_use_result(sql->con);
1.1424 + if (sql->res)
1.1425 + {
1.1426 + /* create references between query results and table fields*/
1.1427 + total = dl_mysql_num_fields(sql->res);
1.1428 + if (total > SQL_FIELD_MAX)
1.1429 + { xprintf("db_mysql_open: Too many fields (> %d) in query.\n"
1.1430 + "\"%s\"\n", SQL_FIELD_MAX, query);
1.1431 + xprintf("%s\n",dl_mysql_error(sql->con));
1.1432 + dl_mysql_close(sql->con);
1.1433 + xfree(query);
1.1434 + xfree(sql);
1.1435 + return NULL;
1.1436 + }
1.1437 + fields = dl_mysql_fetch_fields(sql->res);
1.1438 + for (i = 1; i <= total; i++)
1.1439 + {
1.1440 + for (j = sql->nf; j >= 1; j--)
1.1441 + {
1.1442 + if (strcmp(mpl_tab_get_name(dca, j), fields[i-1].name)
1.1443 + == 0)
1.1444 + break;
1.1445 + }
1.1446 + sql->ref[i] = j;
1.1447 + }
1.1448 + }
1.1449 + else
1.1450 + {
1.1451 + if(dl_mysql_field_count(sql->con) == 0)
1.1452 + {
1.1453 + xprintf("db_mysql_open: Query was not a SELECT\n\"%s\"\n",
1.1454 + query);
1.1455 + xprintf("%s\n",dl_mysql_error(sql->con));
1.1456 + xfree(query);
1.1457 + xfree(sql);
1.1458 + return NULL;
1.1459 + }
1.1460 + else
1.1461 + {
1.1462 + xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
1.1463 + xprintf("%s\n",dl_mysql_error(sql->con));
1.1464 + xfree(query);
1.1465 + xfree(sql);
1.1466 + return NULL;
1.1467 + }
1.1468 + }
1.1469 + }
1.1470 + else if ( sql->mode == 'W' )
1.1471 + { for(j = 0; sqllines[j] != NULL; j++)
1.1472 + arg = (char *) sqllines[j];
1.1473 + if ( NULL != strchr(arg, '?') )
1.1474 + {
1.1475 + total = strlen(arg);
1.1476 + query = xmalloc( (total+1) * sizeof(char));
1.1477 + strcpy (query, arg);
1.1478 + }
1.1479 + else
1.1480 + query = db_generate_insert_stmt(dca);
1.1481 + sql->query = query;
1.1482 + xprintf("%s\n", query);
1.1483 + }
1.1484 + return sql;
1.1485 +}
1.1486 +
1.1487 +int db_mysql_read(TABDCA *dca, void *link)
1.1488 +{ struct db_mysql *sql;
1.1489 + char buf[255+1];
1.1490 + char **row;
1.1491 + unsigned long *lengths;
1.1492 + MYSQL_FIELD *fields;
1.1493 + double num;
1.1494 + int len;
1.1495 + unsigned long num_fields;
1.1496 + int i;
1.1497 +
1.1498 + sql = (struct db_mysql *) link;
1.1499 +
1.1500 + xassert(sql != NULL);
1.1501 + xassert(sql->mode == 'R');
1.1502 + if (NULL == sql->res)
1.1503 + {
1.1504 + xprintf("db_mysql_read: no result set available");
1.1505 + return 1;
1.1506 + }
1.1507 + if (NULL==(row = (char **)dl_mysql_fetch_row(sql->res))) {
1.1508 + return -1; /*EOF*/
1.1509 + }
1.1510 + lengths = dl_mysql_fetch_lengths(sql->res);
1.1511 + fields = dl_mysql_fetch_fields(sql->res);
1.1512 + num_fields = dl_mysql_num_fields(sql->res);
1.1513 + for (i=1; i <= num_fields; i++)
1.1514 + {
1.1515 + if (row[i-1] != NULL)
1.1516 + { len = (size_t) lengths[i-1];
1.1517 + if (len > 255)
1.1518 + len = 255;
1.1519 + strncpy(buf, (const char *) row[i-1], len);
1.1520 + buf[len] = 0x00;
1.1521 + if (0 != (fields[i-1].flags & NUM_FLAG))
1.1522 + { strspx(buf); /* remove spaces*/
1.1523 + if (str2num(buf, &num) != 0)
1.1524 + { xprintf("'%s' cannot be converted to a number.\n", buf);
1.1525 + return 1;
1.1526 + }
1.1527 + if (sql->ref[i] > 0)
1.1528 + mpl_tab_set_num(dca, sql->ref[i], num);
1.1529 + }
1.1530 + else
1.1531 + { if (sql->ref[i] > 0)
1.1532 + mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
1.1533 + }
1.1534 + }
1.1535 + }
1.1536 + return 0;
1.1537 +}
1.1538 +
1.1539 +int db_mysql_write(TABDCA *dca, void *link)
1.1540 +{
1.1541 + struct db_mysql *sql;
1.1542 + char *part;
1.1543 + char *query;
1.1544 + char *template;
1.1545 + char num[50];
1.1546 + int k;
1.1547 + int len;
1.1548 + int nf;
1.1549 +
1.1550 + sql = (struct db_mysql *) link;
1.1551 + xassert(sql != NULL);
1.1552 + xassert(sql->mode == 'W');
1.1553 +
1.1554 + len = strlen(sql->query);
1.1555 + template = (char *) xmalloc( (len + 1) * sizeof(char) );
1.1556 + strcpy(template, sql->query);
1.1557 +
1.1558 + nf = mpl_tab_num_flds(dca);
1.1559 + for (k = 1; k <= nf; k++)
1.1560 + { switch (mpl_tab_get_type(dca, k))
1.1561 + { case 'N':
1.1562 + len += 20;
1.1563 + break;
1.1564 + case 'S':
1.1565 + len += db_escaped_string_length(mpl_tab_get_str(dca, k));
1.1566 + len += 2;
1.1567 + break;
1.1568 + default:
1.1569 + xassert(dca != dca);
1.1570 + }
1.1571 + }
1.1572 + query = xmalloc( (len + 1 ) * sizeof(char) );
1.1573 + query[0] = 0x00;
1.1574 + for (k = 1, part = strtok (template, "?"); (part != NULL);
1.1575 + part = strtok (NULL, "?"), k++)
1.1576 + {
1.1577 + if (k > nf) break;
1.1578 + strcat( query, part );
1.1579 + switch (mpl_tab_get_type(dca, k))
1.1580 + { case 'N':
1.1581 +#if 0 /* 02/XI-2010 by xypron */
1.1582 + sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
1.1583 +#else
1.1584 + sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
1.1585 +#endif
1.1586 + strcat( query, num );
1.1587 + break;
1.1588 + case 'S':
1.1589 + strcat( query, "'");
1.1590 + db_escape_string( query + strlen(query),
1.1591 + mpl_tab_get_str(dca, k) );
1.1592 + strcat( query, "'");
1.1593 + break;
1.1594 + default:
1.1595 + xassert(dca != dca);
1.1596 + }
1.1597 + }
1.1598 + if (part != NULL)
1.1599 + strcat(query, part);
1.1600 + if (dl_mysql_query(sql->con, query))
1.1601 + {
1.1602 + xprintf("db_mysql_write: Query\n\"%s\"\nfailed.\n", query);
1.1603 + xprintf("%s\n",dl_mysql_error(sql->con));
1.1604 + xfree(query);
1.1605 + xfree(template);
1.1606 + return 1;
1.1607 + }
1.1608 +
1.1609 + xfree(query);
1.1610 + xfree(template);
1.1611 + return 0;
1.1612 + }
1.1613 +
1.1614 +int db_mysql_close(TABDCA *dca, void *link)
1.1615 +{
1.1616 + struct db_mysql *sql;
1.1617 +
1.1618 + sql = (struct db_mysql *) link;
1.1619 + xassert(sql != NULL);
1.1620 + dl_mysql_close(sql->con);
1.1621 + if ( sql->mode == 'W' )
1.1622 + xfree(sql->query);
1.1623 + xfree(sql);
1.1624 + dca->link = NULL;
1.1625 + return 0;
1.1626 +}
1.1627 +
1.1628 +#endif
1.1629 +
1.1630 +/* eof */