src/glpsql.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

- Generated files and doc/notes are removed
     1 /* glpsql.c */
     2 
     3 /***********************************************************************
     4 *  This code is part of GLPK (GNU Linear Programming Kit).
     5 *
     6 *  Author: Heinrich Schuchardt <xypron.glpk@gmx.de>.
     7 *
     8 *  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
     9 *  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
    10 *  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
    11 *  E-mail: <mao@gnu.org>.
    12 *
    13 *  GLPK is free software: you can redistribute it and/or modify it
    14 *  under the terms of the GNU General Public License as published by
    15 *  the Free Software Foundation, either version 3 of the License, or
    16 *  (at your option) any later version.
    17 *
    18 *  GLPK is distributed in the hope that it will be useful, but WITHOUT
    19 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    20 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    21 *  License for more details.
    22 *
    23 *  You should have received a copy of the GNU General Public License
    24 *  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
    25 ***********************************************************************/
    26 
    27 #ifdef HAVE_CONFIG_H
    28 #include <config.h>
    29 #endif
    30 
    31 #include "glpmpl.h"
    32 #include "glpsql.h"
    33 
    34 #ifdef ODBC_DLNAME
    35 #define HAVE_ODBC
    36 #define libodbc ODBC_DLNAME
    37 #define h_odbc (get_env_ptr()->h_odbc)
    38 #endif
    39 
    40 #ifdef MYSQL_DLNAME
    41 #define HAVE_MYSQL
    42 #define libmysql MYSQL_DLNAME
    43 #define h_mysql (get_env_ptr()->h_mysql)
    44 #endif
    45 
    46 static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
    47       **sqllines);
    48 static void *db_mysql_open_int(TABDCA *dca, int mode, const char
    49       **sqllines);
    50 
    51 /**********************************************************************/
    52 
    53 #if defined(HAVE_ODBC) || defined(HAVE_MYSQL)
    54 
    55 #define SQL_FIELD_MAX 100
    56 /* maximal field count */
    57 
    58 #define SQL_FDLEN_MAX 255
    59 /* maximal field length */
    60 
    61 /***********************************************************************
    62 *  NAME
    63 *
    64 *  args_concat - concatenate arguments
    65 *
    66 *  SYNOPSIS
    67 *
    68 *  static char **args_concat(TABDCA *dca);
    69 *
    70 *  DESCRIPTION
    71 *
    72 *  The arguments passed in dca are SQL statements. A SQL statement may
    73 *  be split over multiple arguments. The last argument of a SQL
    74 *  statement will be terminated with a semilocon. Each SQL statement is
    75 *  merged into a single zero terminated string. Boundaries between
    76 *  arguments are replaced by space.
    77 *
    78 *  RETURNS
    79 *
    80 *  Buffer with SQL statements */
    81 
    82 static char **args_concat(TABDCA *dca)
    83 {
    84    const char  *arg;
    85    int          i;
    86    int          j;
    87    int          j0;
    88    int          j1;
    89    int          len;
    90    int          lentot;
    91    int          narg;
    92    int          nline = 0;
    93    void        *ret;
    94    char       **sqllines = NULL;
    95 
    96    narg = mpl_tab_num_args(dca);
    97    /* The SQL statements start with argument 3. */
    98    if (narg < 3)
    99       return NULL;
   100    /* Count the SQL statements */
   101    for (j = 3; j <= narg; j++)
   102    {
   103       arg = mpl_tab_get_arg(dca, j);
   104       len = strlen(arg);
   105       if (arg[len-1] == ';' || j == narg)
   106         nline ++;
   107    }
   108    /* Allocate string buffer. */
   109    sqllines = (char **) xmalloc((nline+1) * sizeof(char **));
   110    /* Join arguments */
   111    sqllines[0] = NULL;
   112    j0     = 3;
   113    i      = 0;
   114    lentot = 0;
   115    for (j = 3; j <= narg; j++)
   116    {
   117       arg = mpl_tab_get_arg(dca, j);
   118       len = strlen(arg);
   119       lentot += len;
   120       if (arg[len-1] == ';' || j == narg)
   121       {  /* Join arguments for a single SQL statement */
   122          sqllines[i] = xmalloc(lentot+1);
   123          sqllines[i+1] = NULL;
   124          sqllines[i][0] = 0x00;
   125          for (j1 = j0; j1 <= j; j1++)
   126          {  if(j1>j0)
   127                strcat(sqllines[i], " ");
   128             strcat(sqllines[i], mpl_tab_get_arg(dca, j1));
   129          }
   130          len = strlen(sqllines[i]);
   131          if (sqllines[i][len-1] == ';')
   132             sqllines[i][len-1] = 0x00;
   133          j0 = j+1;
   134          i++;
   135          lentot = 0;
   136       }
   137    }
   138    return sqllines;
   139 }
   140 
   141 /***********************************************************************
   142 *  NAME
   143 *
   144 *  free_buffer - free multiline string buffer
   145 *
   146 *  SYNOPSIS
   147 *
   148 *  static void free_buffer(char **buf);
   149 *
   150 *  DESCRIPTION
   151 *
   152 *  buf is a list of strings terminated by NULL.
   153 *  The memory for the strings and for the list is released. */
   154 
   155 static void free_buffer(char **buf)
   156 {  int i;
   157 
   158    for(i = 0; buf[i] != NULL; i++)
   159       xfree(buf[i]);
   160    xfree(buf);
   161 }
   162 
   163 static int db_escaped_string_length(const char* from)
   164 /* length of escaped string */
   165 {
   166    int         count;
   167    const char *pointer;
   168 
   169     for (pointer = from, count = 0; *pointer != (char) '\0'; pointer++,
   170          count++)
   171     {
   172       switch (*pointer)
   173       {
   174          case '\'':
   175             count++;
   176             break;
   177       }
   178     }
   179 
   180     return count;
   181 }
   182 
   183 static int db_escape_string (char *to, const char *from)
   184 /* escape string*/
   185 {
   186    const char *source = from;
   187    char *target = to;
   188    unsigned int remaining;
   189 
   190    remaining = strlen(from);
   191 
   192    if (to == NULL)
   193      to = (char *) (from + remaining);
   194 
   195    while (remaining > 0)
   196    {
   197       switch (*source)
   198       {
   199          case '\'':
   200             *target = '\'';
   201             target++;
   202             *target = '\'';
   203             break;
   204 
   205          default:
   206             *target = *source;
   207             }
   208       source++;
   209       target++;
   210       remaining--;
   211       }
   212 
   213    /* Write the terminating NUL character. */
   214    *target = '\0';
   215 
   216    return target - to;
   217 }
   218 
   219 static char *db_generate_select_stmt(TABDCA *dca)
   220 /* generate select statement */
   221 {
   222    char        *arg;
   223    char const  *field;
   224    char        *query;
   225    int          j;
   226    int          narg;
   227    int          nf;
   228    int          total;
   229 
   230    total = 50;
   231    nf = mpl_tab_num_flds(dca);
   232    narg = mpl_tab_num_args(dca);
   233    for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
   234    {
   235       field = mpl_tab_get_name(dca, j);
   236       total += strlen(field);
   237       total += 2;
   238    }
   239    arg = (char *) mpl_tab_get_arg(dca, narg);
   240    total += strlen(arg);
   241    query = xmalloc( total * sizeof(char));
   242    strcpy (query, "SELECT ");
   243    for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
   244    {
   245       field = mpl_tab_get_name(dca, j);
   246       strcat(query, field);
   247       if ( j < nf )
   248          strcat(query, ", ");
   249    }
   250    strcat(query, " FROM ");
   251    strcat(query, arg);
   252    return query;
   253 }
   254 
   255 static char *db_generate_insert_stmt(TABDCA *dca)
   256 /* generate insert statement */
   257 {
   258    char        *arg;
   259    char const  *field;
   260    char        *query;
   261    int          j;
   262    int          narg;
   263    int          nf;
   264    int          total;
   265 
   266    total = 50;
   267    nf = mpl_tab_num_flds(dca);
   268    narg = mpl_tab_num_args(dca);
   269    for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
   270    {
   271       field = mpl_tab_get_name(dca, j);
   272       total += strlen(field);
   273       total += 5;
   274    }
   275    arg = (char *) mpl_tab_get_arg(dca, narg);
   276    total += strlen(arg);
   277    query = xmalloc( (total+1) * sizeof(char));
   278    strcpy (query, "INSERT INTO ");
   279    strcat(query, arg);
   280    strcat(query, " ( ");
   281    for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
   282    {
   283       field = mpl_tab_get_name(dca, j);
   284       strcat(query, field);
   285       if ( j < nf )
   286          strcat(query, ", ");
   287    }
   288    strcat(query, " ) VALUES ( ");
   289    for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
   290    {
   291       strcat(query, "?");
   292       if ( j < nf )
   293          strcat(query, ", ");
   294    }
   295    strcat(query, " )");
   296    return query;
   297 }
   298 
   299 #endif
   300 
   301 /**********************************************************************/
   302 
   303 #ifndef HAVE_ODBC
   304 
   305 void *db_iodbc_open(TABDCA *dca, int mode)
   306 {     xassert(dca == dca);
   307       xassert(mode == mode);
   308       xprintf("iODBC table driver not supported\n");
   309       return NULL;
   310 }
   311 
   312 int db_iodbc_read(TABDCA *dca, void *link)
   313 {     xassert(dca != dca);
   314       xassert(link != link);
   315       return 0;
   316 }
   317 
   318 int db_iodbc_write(TABDCA *dca, void *link)
   319 {     xassert(dca != dca);
   320       xassert(link != link);
   321       return 0;
   322 }
   323 
   324 int db_iodbc_close(TABDCA *dca, void *link)
   325 {     xassert(dca != dca);
   326       xassert(link != link);
   327       return 0;
   328 }
   329 
   330 #else
   331 
   332 #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
   333 #include <windows.h>
   334 #endif
   335 
   336 #include <sql.h>
   337 #include <sqlext.h>
   338 
   339 struct db_odbc
   340 {
   341    int              mode;         /*'R' = Read, 'W' = Write*/
   342    SQLHDBC          hdbc;         /*connection handle*/
   343    SQLHENV          henv;         /*environment handle*/
   344    SQLHSTMT         hstmt;        /*statement handle*/
   345    SQLSMALLINT      nresultcols;  /* columns in result*/
   346    SQLULEN          collen[SQL_FIELD_MAX+1];
   347    SQLLEN           outlen[SQL_FIELD_MAX+1];
   348    SQLSMALLINT      coltype[SQL_FIELD_MAX+1];
   349    SQLCHAR          data[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
   350    SQLCHAR          colname[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
   351    int              isnumeric[SQL_FIELD_MAX+1];
   352    int              nf;
   353    /* number of fields in the csv file */
   354    int              ref[1+SQL_FIELD_MAX];
   355    /* ref[k] = k', if k-th field of the csv file corresponds to
   356       k'-th field in the table statement; if ref[k] = 0, k-th field
   357       of the csv file is ignored */
   358    SQLCHAR         *query;
   359    /* query generated by db_iodbc_open */
   360 };
   361 
   362 SQLRETURN SQL_API dl_SQLAllocHandle (
   363    SQLSMALLINT           HandleType,
   364    SQLHANDLE             InputHandle,
   365    SQLHANDLE            *OutputHandle)
   366 {
   367       typedef SQLRETURN SQL_API ep_SQLAllocHandle(
   368          SQLSMALLINT           HandleType,
   369          SQLHANDLE             InputHandle,
   370          SQLHANDLE            *OutputHandle);
   371 
   372       ep_SQLAllocHandle *fn;
   373       fn = (ep_SQLAllocHandle *) xdlsym(h_odbc, "SQLAllocHandle");
   374       xassert(fn != NULL);
   375       return (*fn)(HandleType, InputHandle, OutputHandle);
   376 }
   377 
   378 SQLRETURN SQL_API dl_SQLBindCol (
   379    SQLHSTMT              StatementHandle,
   380    SQLUSMALLINT          ColumnNumber,
   381    SQLSMALLINT           TargetType,
   382    SQLPOINTER            TargetValue,
   383    SQLLEN                BufferLength,
   384    SQLLEN               *StrLen_or_Ind)
   385 {
   386       typedef SQLRETURN SQL_API ep_SQLBindCol(
   387          SQLHSTMT              StatementHandle,
   388          SQLUSMALLINT          ColumnNumber,
   389          SQLSMALLINT           TargetType,
   390          SQLPOINTER            TargetValue,
   391          SQLLEN                BufferLength,
   392          SQLLEN               *StrLen_or_Ind);
   393       ep_SQLBindCol *fn;
   394       fn = (ep_SQLBindCol *) xdlsym(h_odbc, "SQLBindCol");
   395       xassert(fn != NULL);
   396       return (*fn)(StatementHandle, ColumnNumber, TargetType,
   397          TargetValue, BufferLength, StrLen_or_Ind);
   398 }
   399 
   400 SQLRETURN SQL_API dl_SQLCloseCursor (
   401    SQLHSTMT              StatementHandle)
   402 {
   403       typedef SQLRETURN SQL_API ep_SQLCloseCursor (
   404          SQLHSTMT              StatementHandle);
   405 
   406       ep_SQLCloseCursor *fn;
   407       fn = (ep_SQLCloseCursor *) xdlsym(h_odbc, "SQLCloseCursor");
   408       xassert(fn != NULL);
   409       return (*fn)(StatementHandle);
   410 }
   411 
   412 
   413 SQLRETURN SQL_API dl_SQLDisconnect (
   414    SQLHDBC               ConnectionHandle)
   415 {
   416       typedef SQLRETURN SQL_API ep_SQLDisconnect(
   417          SQLHDBC               ConnectionHandle);
   418 
   419       ep_SQLDisconnect *fn;
   420       fn = (ep_SQLDisconnect *) xdlsym(h_odbc, "SQLDisconnect");
   421       xassert(fn != NULL);
   422       return (*fn)(ConnectionHandle);
   423 }
   424 
   425 SQLRETURN SQL_API dl_SQLDriverConnect (
   426    SQLHDBC               hdbc,
   427    SQLHWND               hwnd,
   428    SQLCHAR              *szConnStrIn,
   429    SQLSMALLINT           cbConnStrIn,
   430    SQLCHAR              *szConnStrOut,
   431    SQLSMALLINT           cbConnStrOutMax,
   432    SQLSMALLINT          *pcbConnStrOut,
   433    SQLUSMALLINT          fDriverCompletion)
   434 {
   435       typedef SQLRETURN SQL_API ep_SQLDriverConnect(
   436          SQLHDBC               hdbc,
   437          SQLHWND               hwnd,
   438          SQLCHAR             * szConnStrIn,
   439          SQLSMALLINT           cbConnStrIn,
   440          SQLCHAR             * szConnStrOut,
   441          SQLSMALLINT           cbConnStrOutMax,
   442          SQLSMALLINT         * pcbConnStrOut,
   443          SQLUSMALLINT          fDriverCompletion);
   444 
   445       ep_SQLDriverConnect *fn;
   446       fn = (ep_SQLDriverConnect *) xdlsym(h_odbc, "SQLDriverConnect");
   447       xassert(fn != NULL);
   448       return (*fn)(hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut,
   449          cbConnStrOutMax, pcbConnStrOut, fDriverCompletion);
   450 }
   451 
   452 SQLRETURN SQL_API dl_SQLEndTran (
   453    SQLSMALLINT           HandleType,
   454    SQLHANDLE             Handle,
   455    SQLSMALLINT           CompletionType)
   456 {
   457       typedef SQLRETURN SQL_API ep_SQLEndTran (
   458          SQLSMALLINT           HandleType,
   459          SQLHANDLE             Handle,
   460          SQLSMALLINT           CompletionType);
   461 
   462       ep_SQLEndTran *fn;
   463       fn = (ep_SQLEndTran *) xdlsym(h_odbc, "SQLEndTran");
   464       xassert(fn != NULL);
   465       return (*fn)(HandleType, Handle, CompletionType);
   466 }
   467 
   468 SQLRETURN SQL_API dl_SQLExecDirect (
   469    SQLHSTMT              StatementHandle,
   470    SQLCHAR             * StatementText,
   471    SQLINTEGER            TextLength)
   472 {
   473       typedef SQLRETURN SQL_API ep_SQLExecDirect (
   474          SQLHSTMT              StatementHandle,
   475          SQLCHAR             * StatementText,
   476          SQLINTEGER            TextLength);
   477 
   478       ep_SQLExecDirect *fn;
   479       fn = (ep_SQLExecDirect *) xdlsym(h_odbc, "SQLExecDirect");
   480       xassert(fn != NULL);
   481       return (*fn)(StatementHandle, StatementText, TextLength);
   482 }
   483 
   484 SQLRETURN SQL_API dl_SQLFetch (
   485    SQLHSTMT              StatementHandle)
   486 {
   487       typedef SQLRETURN SQL_API ep_SQLFetch (
   488          SQLHSTMT              StatementHandle);
   489 
   490       ep_SQLFetch *fn;
   491       fn = (ep_SQLFetch*) xdlsym(h_odbc, "SQLFetch");
   492       xassert(fn != NULL);
   493       return (*fn)(StatementHandle);
   494 }
   495 
   496 SQLRETURN SQL_API dl_SQLFreeHandle (
   497    SQLSMALLINT           HandleType,
   498    SQLHANDLE             Handle)
   499 {
   500       typedef SQLRETURN SQL_API ep_SQLFreeHandle (
   501          SQLSMALLINT           HandleType,
   502          SQLHANDLE             Handle);
   503 
   504       ep_SQLFreeHandle *fn;
   505       fn = (ep_SQLFreeHandle *) xdlsym(h_odbc, "SQLFreeHandle");
   506       xassert(fn != NULL);
   507       return (*fn)(HandleType, Handle);
   508 }
   509 
   510 SQLRETURN SQL_API dl_SQLDescribeCol (
   511    SQLHSTMT              StatementHandle,
   512    SQLUSMALLINT          ColumnNumber,
   513    SQLCHAR             * ColumnName,
   514    SQLSMALLINT           BufferLength,
   515    SQLSMALLINT         * NameLength,
   516    SQLSMALLINT         * DataType,
   517    SQLULEN             * ColumnSize,
   518    SQLSMALLINT         * DecimalDigits,
   519    SQLSMALLINT         * Nullable)
   520 {
   521       typedef SQLRETURN SQL_API ep_SQLDescribeCol (
   522          SQLHSTMT              StatementHandle,
   523          SQLUSMALLINT          ColumnNumber,
   524          SQLCHAR              *ColumnName,
   525          SQLSMALLINT           BufferLength,
   526          SQLSMALLINT          *NameLength,
   527          SQLSMALLINT          *DataType,
   528          SQLULEN              *ColumnSize,
   529          SQLSMALLINT          *DecimalDigits,
   530          SQLSMALLINT          *Nullable);
   531 
   532       ep_SQLDescribeCol *fn;
   533       fn = (ep_SQLDescribeCol *) xdlsym(h_odbc, "SQLDescribeCol");
   534       xassert(fn != NULL);
   535       return (*fn)(StatementHandle, ColumnNumber, ColumnName,
   536          BufferLength, NameLength,
   537          DataType, ColumnSize, DecimalDigits, Nullable);
   538 }
   539 
   540 SQLRETURN SQL_API dl_SQLGetDiagRec (
   541    SQLSMALLINT           HandleType,
   542    SQLHANDLE             Handle,
   543    SQLSMALLINT           RecNumber,
   544    SQLCHAR              *Sqlstate,
   545    SQLINTEGER           *NativeError,
   546    SQLCHAR              *MessageText,
   547    SQLSMALLINT           BufferLength,
   548    SQLSMALLINT          *TextLength)
   549 {
   550       typedef SQLRETURN SQL_API ep_SQLGetDiagRec (
   551          SQLSMALLINT           HandleType,
   552          SQLHANDLE             Handle,
   553          SQLSMALLINT           RecNumber,
   554          SQLCHAR              *Sqlstate,
   555          SQLINTEGER           *NativeError,
   556          SQLCHAR              *MessageText,
   557          SQLSMALLINT           BufferLength,
   558          SQLSMALLINT          *TextLength);
   559 
   560       ep_SQLGetDiagRec *fn;
   561       fn = (ep_SQLGetDiagRec *) xdlsym(h_odbc, "SQLGetDiagRec");
   562       xassert(fn != NULL);
   563       return (*fn)(HandleType, Handle, RecNumber, Sqlstate,
   564          NativeError, MessageText, BufferLength, TextLength);
   565 }
   566 
   567 SQLRETURN SQL_API dl_SQLGetInfo (
   568    SQLHDBC               ConnectionHandle,
   569    SQLUSMALLINT          InfoType,
   570    SQLPOINTER            InfoValue,
   571    SQLSMALLINT           BufferLength,
   572    SQLSMALLINT          *StringLength)
   573 {
   574       typedef SQLRETURN SQL_API ep_SQLGetInfo (
   575          SQLHDBC               ConnectionHandle,
   576          SQLUSMALLINT          InfoType,
   577          SQLPOINTER            InfoValue,
   578          SQLSMALLINT           BufferLength,
   579          SQLSMALLINT          *StringLength);
   580 
   581       ep_SQLGetInfo *fn;
   582       fn = (ep_SQLGetInfo *) xdlsym(h_odbc, "SQLGetInfo");
   583       xassert(fn != NULL);
   584       return (*fn)(ConnectionHandle, InfoType, InfoValue, BufferLength,
   585          StringLength);
   586 }
   587 
   588 SQLRETURN SQL_API dl_SQLNumResultCols (
   589    SQLHSTMT              StatementHandle,
   590    SQLSMALLINT          *ColumnCount)
   591 {
   592       typedef SQLRETURN SQL_API ep_SQLNumResultCols (
   593          SQLHSTMT              StatementHandle,
   594          SQLSMALLINT          *ColumnCount);
   595 
   596       ep_SQLNumResultCols *fn;
   597       fn = (ep_SQLNumResultCols *) xdlsym(h_odbc, "SQLNumResultCols");
   598       xassert(fn != NULL);
   599       return (*fn)(StatementHandle, ColumnCount);
   600 }
   601 
   602 SQLRETURN SQL_API dl_SQLSetConnectAttr (
   603    SQLHDBC               ConnectionHandle,
   604    SQLINTEGER            Attribute,
   605    SQLPOINTER            Value,
   606    SQLINTEGER            StringLength)
   607 {
   608       typedef SQLRETURN SQL_API ep_SQLSetConnectAttr (
   609          SQLHDBC               ConnectionHandle,
   610          SQLINTEGER            Attribute,
   611          SQLPOINTER            Value,
   612          SQLINTEGER            StringLength);
   613 
   614       ep_SQLSetConnectAttr *fn;
   615      fn = (ep_SQLSetConnectAttr *) xdlsym(h_odbc, "SQLSetConnectAttr");
   616       xassert(fn != NULL);
   617       return (*fn)(ConnectionHandle, Attribute, Value, StringLength);
   618 }
   619 
   620 SQLRETURN SQL_API dl_SQLSetEnvAttr (
   621    SQLHENV               EnvironmentHandle,
   622    SQLINTEGER            Attribute,
   623    SQLPOINTER            Value,
   624    SQLINTEGER            StringLength)
   625 {
   626       typedef SQLRETURN SQL_API ep_SQLSetEnvAttr (
   627          SQLHENV               EnvironmentHandle,
   628          SQLINTEGER            Attribute,
   629          SQLPOINTER            Value,
   630          SQLINTEGER            StringLength);
   631 
   632       ep_SQLSetEnvAttr *fn;
   633       fn = (ep_SQLSetEnvAttr *) xdlsym(h_odbc, "SQLSetEnvAttr");
   634       xassert(fn != NULL);
   635       return (*fn)(EnvironmentHandle, Attribute, Value, StringLength);
   636 }
   637 
   638 static void extract_error(
   639    char *fn,
   640    SQLHANDLE handle,
   641    SQLSMALLINT type);
   642 
   643 static int is_numeric(
   644     SQLSMALLINT coltype);
   645 
   646 /***********************************************************************
   647 *  NAME
   648 *
   649 *  db_iodbc_open - open connection to ODBC data base
   650 *
   651 *  SYNOPSIS
   652 *
   653 *  #include "glpsql.h"
   654 *  void *db_iodbc_open(TABDCA *dca, int mode);
   655 *
   656 *  DESCRIPTION
   657 *
   658 *  The routine db_iodbc_open opens a connection to an ODBC data base.
   659 *  It then executes the sql statements passed.
   660 *
   661 *  In the case of table read the SELECT statement is executed.
   662 *
   663 *  In the case of table write the INSERT statement is prepared.
   664 *  RETURNS
   665 *
   666 *  The routine returns a pointer to data storage area created. */
   667 void *db_iodbc_open(TABDCA *dca, int mode)
   668 {  void  *ret;
   669    char **sqllines;
   670 
   671    sqllines = args_concat(dca);
   672    if (sqllines == NULL)
   673    {  xprintf("Missing arguments in table statement.\n"
   674               "Please, supply table driver, dsn, and query.\n");
   675       return NULL;
   676    }
   677    ret = db_iodbc_open_int(dca, mode, (const char **) sqllines);
   678    free_buffer(sqllines);
   679    return ret;
   680 }
   681 
   682 static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
   683    **sqllines)
   684 {
   685    struct db_odbc    *sql;
   686    SQLRETURN          ret;
   687    SQLCHAR FAR       *dsn;
   688    SQLCHAR            info[256];
   689    SQLSMALLINT        colnamelen;
   690    SQLSMALLINT        nullable;
   691    SQLSMALLINT        scale;
   692    const char        *arg;
   693    int                narg;
   694    int                i, j;
   695    int                total;
   696 
   697    if (libodbc == NULL)
   698    {
   699       xprintf("No loader for shared ODBC library available\n");
   700       return NULL;
   701    }
   702 
   703    if (h_odbc == NULL)
   704    {
   705       h_odbc = xdlopen(libodbc);
   706       if (h_odbc == NULL)
   707       {  xprintf("unable to open library %s\n", libodbc);
   708          xprintf("%s\n", xerrmsg());
   709          return NULL;
   710       }
   711    }
   712 
   713    sql = (struct db_odbc *) xmalloc(sizeof(struct db_odbc));
   714    if (sql == NULL)
   715          return NULL;
   716 
   717    sql->mode  = mode;
   718    sql->hdbc  = NULL;
   719    sql->henv  = NULL;
   720    sql->hstmt = NULL;
   721    sql->query = NULL;
   722    narg = mpl_tab_num_args(dca);
   723 
   724    dsn = (SQLCHAR FAR *) mpl_tab_get_arg(dca, 2);
   725    /* allocate an environment handle */
   726    ret = dl_SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
   727       &(sql->henv));
   728    /* set attribute to enable application to run as ODBC 3.0
   729       application */
   730    ret = dl_SQLSetEnvAttr(sql->henv, SQL_ATTR_ODBC_VERSION,
   731       (void *) SQL_OV_ODBC3, 0);
   732    /* allocate a connection handle */
   733    ret = dl_SQLAllocHandle(SQL_HANDLE_DBC, sql->henv, &(sql->hdbc));
   734    /* connect */
   735    ret = dl_SQLDriverConnect(sql->hdbc, NULL, dsn, SQL_NTS, NULL, 0,
   736       NULL, SQL_DRIVER_COMPLETE);
   737    if (SQL_SUCCEEDED(ret))
   738    {  /* output information about data base connection */
   739       xprintf("Connected to ");
   740       dl_SQLGetInfo(sql->hdbc, SQL_DBMS_NAME, (SQLPOINTER)info,
   741          sizeof(info), NULL);
   742       xprintf("%s ", info);
   743       dl_SQLGetInfo(sql->hdbc, SQL_DBMS_VER, (SQLPOINTER)info,
   744          sizeof(info), NULL);
   745       xprintf("%s - ", info);
   746       dl_SQLGetInfo(sql->hdbc, SQL_DATABASE_NAME, (SQLPOINTER)info,
   747          sizeof(info), NULL);
   748       xprintf("%s\n", info);
   749    }
   750    else
   751    {  /* describe error */
   752       xprintf("Failed to connect\n");
   753       extract_error("SQLDriverConnect", sql->hdbc, SQL_HANDLE_DBC);
   754       dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
   755       dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
   756       xfree(sql);
   757       return NULL;
   758    }
   759    /* set AUTOCOMMIT on*/
   760    ret = dl_SQLSetConnectAttr(sql->hdbc, SQL_ATTR_AUTOCOMMIT,
   761       (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0);
   762    /* allocate a statement handle */
   763    ret = dl_SQLAllocHandle(SQL_HANDLE_STMT, sql->hdbc, &(sql->hstmt));
   764 
   765    /* initialization queries */
   766    for(j = 0; sqllines[j+1] != NULL; j++)
   767    {
   768       sql->query = (SQLCHAR *) sqllines[j];
   769       xprintf("%s\n", sql->query);
   770       ret = dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS);
   771       switch (ret)
   772       {
   773          case SQL_SUCCESS:
   774          case SQL_SUCCESS_WITH_INFO:
   775          case SQL_NO_DATA_FOUND:
   776             break;
   777          default:
   778             xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n",
   779                sql->query);
   780             extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
   781             dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
   782             dl_SQLDisconnect(sql->hdbc);
   783             dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
   784             dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
   785             xfree(sql);
   786             return NULL;
   787       }
   788       /* commit statement */
   789       dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
   790    }
   791 
   792    if ( sql->mode == 'R' )
   793    {  sql->nf = mpl_tab_num_flds(dca);
   794       for(j = 0; sqllines[j] != NULL; j++)
   795          arg = sqllines[j];
   796       total = strlen(arg);
   797       if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
   798       {
   799          total = strlen(arg);
   800          sql->query = xmalloc( (total+1) * sizeof(char));
   801          strcpy (sql->query, arg);
   802       }
   803       else
   804       {
   805          sql->query = db_generate_select_stmt(dca);
   806       }
   807       xprintf("%s\n", sql->query);
   808       if (dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS) !=
   809          SQL_SUCCESS)
   810       {
   811          xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n", sql->query);
   812          extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
   813          dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
   814          dl_SQLDisconnect(sql->hdbc);
   815          dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
   816          dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
   817          xfree(sql->query);
   818             xfree(sql);
   819          return NULL;
   820       }
   821       xfree(sql->query);
   822       /* determine number of result columns */
   823       ret = dl_SQLNumResultCols(sql->hstmt, &sql->nresultcols);
   824       total = sql->nresultcols;
   825       if (total > SQL_FIELD_MAX)
   826       {  xprintf("db_iodbc_open: Too many fields (> %d) in query.\n"
   827             "\"%s\"\n", SQL_FIELD_MAX, sql->query);
   828          dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
   829          dl_SQLDisconnect(sql->hdbc);
   830          dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
   831          dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
   832          xfree(sql->query);
   833          return NULL;
   834       }
   835       for (i = 1; i <= total; i++)
   836       {  /* return a set of attributes for a column */
   837          ret = dl_SQLDescribeCol(sql->hstmt, (SQLSMALLINT) i,
   838             sql->colname[i], SQL_FDLEN_MAX,
   839             &colnamelen, &(sql->coltype[i]), &(sql->collen[i]), &scale,
   840             &nullable);
   841          sql->isnumeric[i] = is_numeric(sql->coltype[i]);
   842          /* bind columns to program vars, converting all types to CHAR*/
   843          dl_SQLBindCol(sql->hstmt, i, SQL_CHAR, sql->data[i],
   844             SQL_FDLEN_MAX, &(sql->outlen[i]));
   845          for (j = sql->nf; j >= 1; j--)
   846          {  if (strcmp(mpl_tab_get_name(dca, j), sql->colname[i]) == 0)
   847             break;
   848          }
   849          sql->ref[i] = j;
   850       }
   851    }
   852    else if ( sql->mode == 'W' )
   853    {  for(j = 0; sqllines[j] != NULL; j++)
   854          arg = sqllines[j];
   855       if (  NULL != strchr(arg, '?') )
   856       {
   857          total = strlen(arg);
   858          sql->query = xmalloc( (total+1) * sizeof(char));
   859          strcpy (sql->query, arg);
   860          }
   861       else
   862       {
   863          sql->query = db_generate_insert_stmt(dca);
   864       }
   865       xprintf("%s\n", sql->query);
   866    }
   867    return sql;
   868 }
   869 
   870 int db_iodbc_read(TABDCA *dca, void *link)
   871 {
   872    struct db_odbc  *sql;
   873    SQLRETURN        ret;
   874    char             buf[SQL_FDLEN_MAX+1];
   875    int              i;
   876    int              len;
   877    double           num;
   878 
   879    sql = (struct db_odbc *) link;
   880 
   881    xassert(sql != NULL);
   882    xassert(sql->mode == 'R');
   883 
   884    ret=dl_SQLFetch(sql->hstmt);
   885    if (ret== SQL_ERROR)
   886       return -1;
   887    if (ret== SQL_NO_DATA_FOUND)
   888       return -1; /*EOF*/
   889    for (i=1; i <= sql->nresultcols; i++)
   890    {
   891       if (sql->ref[i] > 0)
   892       {
   893          len = sql->outlen[i];
   894          if (len != SQL_NULL_DATA)
   895          {
   896             if (len > SQL_FDLEN_MAX)
   897                len = SQL_FDLEN_MAX;
   898             else if (len < 0)
   899                len = 0;
   900             strncpy(buf, (const char *) sql->data[i], len);
   901             buf[len] = 0x00;
   902             if (0 != (sql->isnumeric[i]))
   903             {  strspx(buf); /* remove spaces*/
   904                if (str2num(buf, &num) != 0)
   905                {  xprintf("'%s' cannot be converted to a number.\n",
   906                      buf);
   907                   return 1;
   908                }
   909                mpl_tab_set_num(dca, sql->ref[i], num);
   910             }
   911             else
   912             {  mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
   913             }
   914          }
   915       }
   916    }
   917    return 0;
   918 }
   919 
   920 int db_iodbc_write(TABDCA *dca, void *link)
   921 {
   922    struct db_odbc  *sql;
   923    char            *part;
   924    char            *query;
   925    char            *template;
   926    char             num[50];
   927    int              k;
   928    int              len;
   929    int              nf;
   930 
   931    sql = (struct db_odbc *) link;
   932    xassert(sql != NULL);
   933    xassert(sql->mode == 'W');
   934 
   935    len      = strlen(sql->query);
   936    template = (char *) xmalloc( (len + 1) * sizeof(char) );
   937    strcpy(template, sql->query);
   938 
   939    nf = mpl_tab_num_flds(dca);
   940    for (k = 1; k <= nf; k++)
   941    {     switch (mpl_tab_get_type(dca, k))
   942       {  case 'N':
   943             len += 20;
   944             break;
   945          case 'S':
   946             len += db_escaped_string_length(mpl_tab_get_str(dca, k));
   947             len += 2;
   948             break;
   949               default:
   950                         xassert(dca != dca);
   951          }
   952    }
   953    query = xmalloc( (len + 1 ) * sizeof(char) );
   954    query[0] = 0x00;
   955    for (k = 1, part = strtok (template, "?"); (part != NULL);
   956       part = strtok (NULL, "?"), k++)
   957    {
   958       if (k > nf) break;
   959       strcat( query, part );
   960       switch (mpl_tab_get_type(dca, k))
   961       {  case 'N':
   962 #if 0 /* 02/XI-2010 by xypron */
   963             sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
   964 #else
   965             sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
   966 #endif
   967             strcat( query, num );
   968             break;
   969          case 'S':
   970             strcat( query, "'");
   971             db_escape_string( query + strlen(query),
   972                mpl_tab_get_str(dca, k) );
   973             strcat( query, "'");
   974             break;
   975               default:
   976                         xassert(dca != dca);
   977          }
   978    }
   979    if (part != NULL)
   980       strcat(query, part);
   981    if (dl_SQLExecDirect(sql->hstmt, (SQLCHAR *) query, SQL_NTS)
   982       != SQL_SUCCESS)
   983    {
   984       xprintf("db_iodbc_write: Query\n\"%s\"\nfailed.\n", query);
   985       extract_error("SQLExecDirect", sql->hdbc, SQL_HANDLE_DBC);
   986       xfree(query);
   987       xfree(template);
   988       return 1;
   989       }
   990 
   991    xfree(query);
   992    xfree(template);
   993    return 0;
   994 }
   995 
   996 int db_iodbc_close(TABDCA *dca, void *link)
   997 {
   998    struct db_odbc *sql;
   999 
  1000    sql = (struct db_odbc *) link;
  1001    xassert(sql != NULL);
  1002    /* Commit */
  1003    if ( sql->mode == 'W' )
  1004       dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
  1005    if ( sql->mode == 'R' )
  1006       dl_SQLCloseCursor(sql->hstmt);
  1007 
  1008    dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
  1009    dl_SQLDisconnect(sql->hdbc);
  1010    dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
  1011    dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
  1012    if ( sql->mode == 'W' )
  1013       xfree(sql->query);
  1014    xfree(sql);
  1015    dca->link = NULL;
  1016    return 0;
  1017 }
  1018 
  1019 static void extract_error(
  1020    char *fn,
  1021    SQLHANDLE handle,
  1022    SQLSMALLINT type)
  1023 {
  1024    SQLINTEGER   i = 0;
  1025    SQLINTEGER   native;
  1026    SQLCHAR   state[ 7 ];
  1027    SQLCHAR   text[256];
  1028    SQLSMALLINT  len;
  1029    SQLRETURN    ret;
  1030 
  1031    xprintf("\nThe driver reported the following diagnostics whilst "
  1032       "running %s\n", fn);
  1033 
  1034    do
  1035    {
  1036       ret = dl_SQLGetDiagRec(type, handle, ++i, state, &native, text,
  1037          sizeof(text), &len );
  1038       if (SQL_SUCCEEDED(ret))
  1039          xprintf("%s:%ld:%ld:%s\n", state, i, native, text);
  1040    }
  1041    while( ret == SQL_SUCCESS );
  1042 }
  1043 
  1044 static int is_numeric(SQLSMALLINT coltype)
  1045 {
  1046    int ret = 0;
  1047    switch (coltype)
  1048    {
  1049       case SQL_DECIMAL:
  1050       case SQL_NUMERIC:
  1051       case SQL_SMALLINT:
  1052       case SQL_INTEGER:
  1053       case SQL_REAL:
  1054       case SQL_FLOAT:
  1055       case SQL_DOUBLE:
  1056       case SQL_TINYINT:
  1057       case SQL_BIGINT:
  1058          ret = 1;
  1059          break;
  1060    }
  1061    return ret;
  1062 }
  1063 
  1064 #endif
  1065 
  1066 /**********************************************************************/
  1067 
  1068 #ifndef HAVE_MYSQL
  1069 
  1070 void *db_mysql_open(TABDCA *dca, int mode)
  1071 {     xassert(dca == dca);
  1072       xassert(mode == mode);
  1073       xprintf("MySQL table driver not supported\n");
  1074       return NULL;
  1075 }
  1076 
  1077 int db_mysql_read(TABDCA *dca, void *link)
  1078 {     xassert(dca != dca);
  1079       xassert(link != link);
  1080       return 0;
  1081 }
  1082 
  1083 int db_mysql_write(TABDCA *dca, void *link)
  1084 {     xassert(dca != dca);
  1085       xassert(link != link);
  1086       return 0;
  1087 }
  1088 
  1089 int db_mysql_close(TABDCA *dca, void *link)
  1090 {     xassert(dca != dca);
  1091       xassert(link != link);
  1092       return 0;
  1093 }
  1094 
  1095 #else
  1096 
  1097 #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
  1098 #include <windows.h>
  1099 #endif
  1100 
  1101 #ifdef __CYGWIN__
  1102 #define byte_defined 1
  1103 #endif
  1104 
  1105 #include <my_global.h>
  1106 #include <my_sys.h>
  1107 #include <mysql.h>
  1108 
  1109 struct db_mysql
  1110 {
  1111    int              mode;  /*'R' = Read, 'W' = Write*/
  1112    MYSQL           *con;   /*connection*/
  1113    MYSQL_RES       *res;    /*result*/
  1114    int              nf;
  1115    /* number of fields in the csv file */
  1116    int              ref[1+SQL_FIELD_MAX];
  1117    /* ref[k] = k', if k-th field of the csv file corresponds to
  1118       k'-th field in the table statement; if ref[k] = 0, k-th field
  1119       of the csv file is ignored */
  1120    char            *query;
  1121    /* query generated by db_mysql_open */
  1122 };
  1123 
  1124 void STDCALL dl_mysql_close(MYSQL *sock)
  1125 {
  1126       typedef void STDCALL ep_mysql_close(MYSQL *sock);
  1127 
  1128       ep_mysql_close *fn;
  1129       fn = (ep_mysql_close *) xdlsym(h_mysql, "mysql_close");
  1130       xassert(fn != NULL);
  1131       return (*fn)(sock);
  1132 }
  1133 
  1134 const char * STDCALL dl_mysql_error(MYSQL *mysql)
  1135 {
  1136       typedef const char * STDCALL ep_mysql_error(MYSQL *mysql);
  1137 
  1138       ep_mysql_error *fn;
  1139       fn = (ep_mysql_error *) xdlsym(h_mysql, "mysql_error");
  1140       xassert(fn != NULL);
  1141       return (*fn)(mysql);
  1142 }
  1143 
  1144 MYSQL_FIELD * STDCALL dl_mysql_fetch_fields(MYSQL_RES *res)
  1145 {
  1146       typedef MYSQL_FIELD * STDCALL
  1147          ep_mysql_fetch_fields(MYSQL_RES *res);
  1148 
  1149       ep_mysql_fetch_fields *fn;
  1150    fn = (ep_mysql_fetch_fields *) xdlsym(h_mysql, "mysql_fetch_fields");
  1151       xassert(fn != NULL);
  1152       return (*fn)(res);
  1153 }
  1154 
  1155 unsigned long * STDCALL dl_mysql_fetch_lengths(MYSQL_RES *result)
  1156 {
  1157       typedef unsigned long * STDCALL
  1158          ep_mysql_fetch_lengths(MYSQL_RES *result);
  1159 
  1160       ep_mysql_fetch_lengths *fn;
  1161       fn = (ep_mysql_fetch_lengths *) xdlsym(h_mysql,
  1162          "mysql_fetch_lengths");
  1163       xassert(fn != NULL);
  1164       return (*fn)(result);
  1165 }
  1166 
  1167 MYSQL_ROW STDCALL dl_mysql_fetch_row(MYSQL_RES *result)
  1168 {
  1169       typedef MYSQL_ROW STDCALL ep_mysql_fetch_row(MYSQL_RES *result);
  1170 
  1171       ep_mysql_fetch_row *fn;
  1172       fn = (ep_mysql_fetch_row *) xdlsym(h_mysql, "mysql_fetch_row");
  1173       xassert(fn != NULL);
  1174       return (*fn)(result);
  1175 }
  1176 
  1177 unsigned int STDCALL dl_mysql_field_count(MYSQL *mysql)
  1178 {
  1179       typedef unsigned int STDCALL ep_mysql_field_count(MYSQL *mysql);
  1180 
  1181       ep_mysql_field_count *fn;
  1182      fn = (ep_mysql_field_count *) xdlsym(h_mysql, "mysql_field_count");
  1183       xassert(fn != NULL);
  1184       return (*fn)(mysql);
  1185 }
  1186 
  1187 MYSQL * STDCALL dl_mysql_init(MYSQL *mysql)
  1188 {
  1189       typedef MYSQL * STDCALL ep_mysql_init(MYSQL *mysql);
  1190 
  1191       ep_mysql_init *fn;
  1192       fn = (ep_mysql_init *) xdlsym(h_mysql, "mysql_init");
  1193       xassert(fn != NULL);
  1194       return (*fn)(mysql);
  1195 }
  1196 
  1197 unsigned int STDCALL dl_mysql_num_fields(MYSQL_RES *res)
  1198 {
  1199       typedef unsigned int STDCALL ep_mysql_num_fields(MYSQL_RES *res);
  1200 
  1201       ep_mysql_num_fields *fn;
  1202       fn = (ep_mysql_num_fields *) xdlsym(h_mysql, "mysql_num_fields");
  1203       xassert(fn != NULL);
  1204       return (*fn)(res);
  1205 }
  1206 
  1207 int STDCALL dl_mysql_query(MYSQL *mysql, const char *q)
  1208 {
  1209       typedef int STDCALL ep_mysql_query(MYSQL *mysql, const char *q);
  1210 
  1211       ep_mysql_query *fn;
  1212       fn = (ep_mysql_query *) xdlsym(h_mysql, "mysql_query");
  1213       xassert(fn != NULL);
  1214       return (*fn)(mysql, q);
  1215 }
  1216 
  1217 MYSQL * STDCALL dl_mysql_real_connect(MYSQL *mysql, const char *host,
  1218                                            const char *user,
  1219                                            const char *passwd,
  1220                                            const char *db,
  1221                                            unsigned int port,
  1222                                            const char *unix_socket,
  1223                                            unsigned long clientflag)
  1224 {
  1225       typedef MYSQL * STDCALL ep_mysql_real_connect(MYSQL *mysql,
  1226             const char *host,
  1227             const char *user,
  1228             const char *passwd,
  1229             const char *db,
  1230             unsigned int port,
  1231             const char *unix_socket,
  1232             unsigned long clientflag);
  1233 
  1234       ep_mysql_real_connect *fn;
  1235       fn = (ep_mysql_real_connect *) xdlsym(h_mysql,
  1236          "mysql_real_connect");
  1237       xassert(fn != NULL);
  1238       return (*fn)(mysql, host, user, passwd, db, port, unix_socket,
  1239          clientflag);
  1240 }
  1241 
  1242 MYSQL_RES * STDCALL dl_mysql_use_result(MYSQL *mysql)
  1243 {
  1244       typedef MYSQL_RES * STDCALL ep_mysql_use_result(MYSQL *mysql);
  1245       ep_mysql_use_result *fn;
  1246       fn = (ep_mysql_use_result *) xdlsym(h_mysql, "mysql_use_result");
  1247       xassert(fn != NULL);
  1248       return (*fn)(mysql);
  1249 }
  1250 
  1251 /***********************************************************************
  1252 *  NAME
  1253 *
  1254 *  db_mysql_open - open connection to ODBC data base
  1255 *
  1256 *  SYNOPSIS
  1257 *
  1258 *  #include "glpsql.h"
  1259 *  void *db_mysql_open(TABDCA *dca, int mode);
  1260 *
  1261 *  DESCRIPTION
  1262 *
  1263 *  The routine db_mysql_open opens a connection to a MySQL data base.
  1264 *  It then executes the sql statements passed.
  1265 *
  1266 *  In the case of table read the SELECT statement is executed.
  1267 *
  1268 *  In the case of table write the INSERT statement is prepared.
  1269 *  RETURNS
  1270 *
  1271 *  The routine returns a pointer to data storage area created. */
  1272 
  1273 void *db_mysql_open(TABDCA *dca, int mode)
  1274 {  void  *ret;
  1275    char **sqllines;
  1276 
  1277    sqllines = args_concat(dca);
  1278    if (sqllines == NULL)
  1279    {  xprintf("Missing arguments in table statement.\n"
  1280               "Please, supply table driver, dsn, and query.\n");
  1281       return NULL;
  1282    }
  1283    ret = db_mysql_open_int(dca, mode, (const char **) sqllines);
  1284    free_buffer(sqllines);
  1285    return ret;
  1286 }
  1287 
  1288 static void *db_mysql_open_int(TABDCA *dca, int mode, const char
  1289    **sqllines)
  1290 {
  1291    struct db_mysql *sql = NULL;
  1292    char            *arg = NULL;
  1293    const char      *field;
  1294    MYSQL_FIELD     *fields;
  1295    char            *keyword;
  1296    char            *value;
  1297    char            *query;
  1298    char            *dsn;
  1299 /* "Server=[server_name];Database=[database_name];UID=[username];*/
  1300 /* PWD=[password];Port=[port]"*/
  1301    char            *server   = NULL;        /* Server */
  1302    char            *user     = NULL;        /* UID */
  1303    char            *password = NULL;        /* PWD */
  1304    char            *database = NULL;        /* Database */
  1305    unsigned int     port = 0;               /* Port */
  1306    int              narg;
  1307    int              i, j, total;
  1308 
  1309    if (libmysql == NULL)
  1310    {
  1311       xprintf("No loader for shared MySQL library available\n");
  1312       return NULL;
  1313    }
  1314 
  1315    if (h_mysql == NULL)
  1316    {
  1317       h_mysql = xdlopen(libmysql);
  1318       if (h_mysql == NULL)
  1319       {  xprintf("unable to open library %s\n", libmysql);
  1320          xprintf("%s\n", xerrmsg());
  1321          return NULL;
  1322       }
  1323    }
  1324 
  1325    sql = (struct db_mysql *) xmalloc(sizeof(struct db_mysql));
  1326    if (sql == NULL)
  1327          return NULL;
  1328    sql->mode = mode;
  1329    sql->res = NULL;
  1330    sql->query = NULL;
  1331    sql->nf = mpl_tab_num_flds(dca);
  1332 
  1333    narg = mpl_tab_num_args(dca);
  1334    if (narg < 3 )
  1335       xprintf("MySQL driver: string list too short \n");
  1336 
  1337    /* get connection string*/
  1338    dsn = (char *) mpl_tab_get_arg(dca, 2);
  1339       /* copy connection string*/
  1340    i = strlen(dsn);
  1341    i++;
  1342    arg = xmalloc(i * sizeof(char));
  1343    strcpy(arg, dsn);
  1344    /*tokenize connection string*/
  1345    for (i = 1, keyword = strtok (arg, "="); (keyword != NULL);
  1346       keyword = strtok (NULL, "="), i++)
  1347    {
  1348          value = strtok (NULL, ";");
  1349       if (value==NULL)
  1350          {
  1351             xprintf("db_mysql_open: Missing value for keyword %s\n",
  1352                keyword);
  1353             xfree(arg);
  1354             xfree(sql);
  1355             return NULL;
  1356       }
  1357       if (0 == strcmp(keyword, "Server"))
  1358             server = value;
  1359       else if (0 == strcmp(keyword, "Database"))
  1360              database = value;
  1361       else if (0 == strcmp(keyword, "UID"))
  1362              user = value;
  1363       else if (0 == strcmp(keyword, "PWD"))
  1364              password = value;
  1365       else if (0 == strcmp(keyword, "Port"))
  1366              port = (unsigned int) atol(value);
  1367    }
  1368    /* Connect to database */
  1369    sql->con = dl_mysql_init(NULL);
  1370   if (!dl_mysql_real_connect(sql->con, server, user, password, database,
  1371       port, NULL, 0))
  1372    {
  1373       xprintf("db_mysql_open: Connect failed\n");
  1374       xprintf("%s\n", dl_mysql_error(sql->con));
  1375       xfree(arg);
  1376       xfree(sql);
  1377       return NULL;
  1378    }
  1379    xfree(arg);
  1380 
  1381    for(j = 0; sqllines[j+1] != NULL; j++)
  1382    {  query = (char *) sqllines[j];
  1383       xprintf("%s\n", query);
  1384       if (dl_mysql_query(sql->con, query))
  1385       {
  1386          xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
  1387          xprintf("%s\n",dl_mysql_error(sql->con));
  1388          dl_mysql_close(sql->con);
  1389          xfree(sql);
  1390          return NULL;
  1391       }
  1392    }
  1393 
  1394    if ( sql->mode == 'R' )
  1395    {  sql->nf = mpl_tab_num_flds(dca);
  1396       for(j = 0; sqllines[j] != NULL; j++)
  1397          arg = (char *) sqllines[j];
  1398       total = strlen(arg);
  1399       if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
  1400       {
  1401          total = strlen(arg);
  1402          query = xmalloc( (total+1) * sizeof(char));
  1403          strcpy (query, arg);
  1404       }
  1405       else
  1406       {
  1407          query = db_generate_select_stmt(dca);
  1408       }
  1409       xprintf("%s\n", query);
  1410       if (dl_mysql_query(sql->con, query))
  1411       {
  1412          xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
  1413          xprintf("%s\n",dl_mysql_error(sql->con));
  1414          dl_mysql_close(sql->con);
  1415          xfree(query);
  1416          xfree(sql);
  1417          return NULL;
  1418       }
  1419       xfree(query);
  1420       sql->res = dl_mysql_use_result(sql->con);
  1421       if (sql->res)
  1422       {
  1423          /* create references between query results and table fields*/
  1424          total = dl_mysql_num_fields(sql->res);
  1425          if (total > SQL_FIELD_MAX)
  1426          {  xprintf("db_mysql_open: Too many fields (> %d) in query.\n"
  1427                "\"%s\"\n", SQL_FIELD_MAX, query);
  1428             xprintf("%s\n",dl_mysql_error(sql->con));
  1429             dl_mysql_close(sql->con);
  1430             xfree(query);
  1431                  xfree(sql);
  1432             return NULL;
  1433          }
  1434          fields = dl_mysql_fetch_fields(sql->res);
  1435          for (i = 1; i <= total; i++)
  1436          {
  1437                for (j = sql->nf; j >= 1; j--)
  1438             {
  1439                if (strcmp(mpl_tab_get_name(dca, j), fields[i-1].name)
  1440                   == 0)
  1441                break;
  1442             }
  1443             sql->ref[i] = j;
  1444          }
  1445       }
  1446       else
  1447       {
  1448          if(dl_mysql_field_count(sql->con) == 0)
  1449             {
  1450             xprintf("db_mysql_open: Query was not a SELECT\n\"%s\"\n",
  1451                query);
  1452             xprintf("%s\n",dl_mysql_error(sql->con));
  1453             xfree(query);
  1454             xfree(sql);
  1455             return NULL;
  1456          }
  1457          else
  1458          {
  1459             xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
  1460             xprintf("%s\n",dl_mysql_error(sql->con));
  1461             xfree(query);
  1462             xfree(sql);
  1463             return NULL;
  1464          }
  1465       }
  1466    }
  1467    else if ( sql->mode == 'W' )
  1468    {  for(j = 0; sqllines[j] != NULL; j++)
  1469          arg = (char *) sqllines[j];
  1470       if (  NULL != strchr(arg, '?') )
  1471       {
  1472          total = strlen(arg);
  1473          query = xmalloc( (total+1) * sizeof(char));
  1474          strcpy (query, arg);
  1475          }
  1476       else
  1477          query = db_generate_insert_stmt(dca);
  1478       sql->query = query;
  1479       xprintf("%s\n", query);
  1480    }
  1481    return sql;
  1482 }
  1483 
  1484 int db_mysql_read(TABDCA *dca, void *link)
  1485 {  struct db_mysql *sql;
  1486    char            buf[255+1];
  1487    char            **row;
  1488    unsigned long   *lengths;
  1489    MYSQL_FIELD     *fields;
  1490    double          num;
  1491    int             len;
  1492    unsigned long   num_fields;
  1493    int             i;
  1494 
  1495    sql = (struct db_mysql *) link;
  1496 
  1497    xassert(sql != NULL);
  1498    xassert(sql->mode == 'R');
  1499    if (NULL == sql->res)
  1500    {
  1501       xprintf("db_mysql_read: no result set available");
  1502       return 1;
  1503    }
  1504    if (NULL==(row = (char **)dl_mysql_fetch_row(sql->res))) {
  1505        return -1; /*EOF*/
  1506    }
  1507    lengths = dl_mysql_fetch_lengths(sql->res);
  1508    fields = dl_mysql_fetch_fields(sql->res);
  1509    num_fields = dl_mysql_num_fields(sql->res);
  1510    for (i=1; i <= num_fields; i++)
  1511    {
  1512       if (row[i-1] != NULL)
  1513       {  len = (size_t) lengths[i-1];
  1514          if (len > 255)
  1515             len = 255;
  1516          strncpy(buf, (const char *) row[i-1], len);
  1517          buf[len] = 0x00;
  1518          if (0 != (fields[i-1].flags & NUM_FLAG))
  1519          {  strspx(buf); /* remove spaces*/
  1520             if (str2num(buf, &num) != 0)
  1521             {  xprintf("'%s' cannot be converted to a number.\n", buf);
  1522                return 1;
  1523             }
  1524             if (sql->ref[i] > 0)
  1525                mpl_tab_set_num(dca, sql->ref[i], num);
  1526          }
  1527          else
  1528          {  if (sql->ref[i] > 0)
  1529                mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
  1530          }
  1531       }
  1532    }
  1533    return 0;
  1534 }
  1535 
  1536 int db_mysql_write(TABDCA *dca, void *link)
  1537 {
  1538    struct db_mysql *sql;
  1539    char            *part;
  1540    char            *query;
  1541    char            *template;
  1542    char             num[50];
  1543    int              k;
  1544    int              len;
  1545    int              nf;
  1546 
  1547    sql = (struct db_mysql *) link;
  1548    xassert(sql != NULL);
  1549    xassert(sql->mode == 'W');
  1550 
  1551    len      = strlen(sql->query);
  1552    template = (char *) xmalloc( (len + 1) * sizeof(char) );
  1553    strcpy(template, sql->query);
  1554 
  1555    nf = mpl_tab_num_flds(dca);
  1556    for (k = 1; k <= nf; k++)
  1557    {     switch (mpl_tab_get_type(dca, k))
  1558       {  case 'N':
  1559             len += 20;
  1560             break;
  1561          case 'S':
  1562             len += db_escaped_string_length(mpl_tab_get_str(dca, k));
  1563             len += 2;
  1564             break;
  1565               default:
  1566                         xassert(dca != dca);
  1567          }
  1568    }
  1569    query = xmalloc( (len + 1 ) * sizeof(char) );
  1570    query[0] = 0x00;
  1571    for (k = 1, part = strtok (template, "?"); (part != NULL);
  1572       part = strtok (NULL, "?"), k++)
  1573    {
  1574       if (k > nf) break;
  1575       strcat( query, part );
  1576       switch (mpl_tab_get_type(dca, k))
  1577       {  case 'N':
  1578 #if 0 /* 02/XI-2010 by xypron */
  1579             sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
  1580 #else
  1581             sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
  1582 #endif
  1583             strcat( query, num );
  1584             break;
  1585          case 'S':
  1586             strcat( query, "'");
  1587             db_escape_string( query + strlen(query),
  1588                mpl_tab_get_str(dca, k) );
  1589             strcat( query, "'");
  1590             break;
  1591               default:
  1592                         xassert(dca != dca);
  1593          }
  1594    }
  1595    if (part != NULL)
  1596       strcat(query, part);
  1597    if (dl_mysql_query(sql->con, query))
  1598    {
  1599       xprintf("db_mysql_write: Query\n\"%s\"\nfailed.\n", query);
  1600       xprintf("%s\n",dl_mysql_error(sql->con));
  1601       xfree(query);
  1602       xfree(template);
  1603       return 1;
  1604       }
  1605 
  1606    xfree(query);
  1607    xfree(template);
  1608    return 0;
  1609    }
  1610 
  1611 int db_mysql_close(TABDCA *dca, void *link)
  1612 {
  1613    struct db_mysql *sql;
  1614 
  1615    sql = (struct db_mysql *) link;
  1616    xassert(sql != NULL);
  1617    dl_mysql_close(sql->con);
  1618    if ( sql->mode == 'W' )
  1619       xfree(sql->query);
  1620    xfree(sql);
  1621    dca->link = NULL;
  1622    return 0;
  1623 }
  1624 
  1625 #endif
  1626 
  1627 /* eof */