src/glpsql.c
changeset 1 c445c931472f
     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 */