alpar@1: /* glpsql.c */ alpar@1: alpar@1: /*********************************************************************** alpar@1: * This code is part of GLPK (GNU Linear Programming Kit). alpar@1: * alpar@1: * Author: Heinrich Schuchardt . alpar@1: * alpar@1: * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, alpar@1: * 2009, 2010 Andrew Makhorin, Department for Applied Informatics, alpar@1: * Moscow Aviation Institute, Moscow, Russia. All rights reserved. alpar@1: * E-mail: . alpar@1: * alpar@1: * GLPK is free software: you can redistribute it and/or modify it alpar@1: * under the terms of the GNU General Public License as published by alpar@1: * the Free Software Foundation, either version 3 of the License, or alpar@1: * (at your option) any later version. alpar@1: * alpar@1: * GLPK is distributed in the hope that it will be useful, but WITHOUT alpar@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY alpar@1: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public alpar@1: * License for more details. alpar@1: * alpar@1: * You should have received a copy of the GNU General Public License alpar@1: * along with GLPK. If not, see . alpar@1: ***********************************************************************/ alpar@1: alpar@1: #ifdef HAVE_CONFIG_H alpar@1: #include alpar@1: #endif alpar@1: alpar@1: #include "glpmpl.h" alpar@1: #include "glpsql.h" alpar@1: alpar@1: #ifdef ODBC_DLNAME alpar@1: #define HAVE_ODBC alpar@1: #define libodbc ODBC_DLNAME alpar@1: #define h_odbc (get_env_ptr()->h_odbc) alpar@1: #endif alpar@1: alpar@1: #ifdef MYSQL_DLNAME alpar@1: #define HAVE_MYSQL alpar@1: #define libmysql MYSQL_DLNAME alpar@1: #define h_mysql (get_env_ptr()->h_mysql) alpar@1: #endif alpar@1: alpar@1: static void *db_iodbc_open_int(TABDCA *dca, int mode, const char alpar@1: **sqllines); alpar@1: static void *db_mysql_open_int(TABDCA *dca, int mode, const char alpar@1: **sqllines); alpar@1: alpar@1: /**********************************************************************/ alpar@1: alpar@1: #if defined(HAVE_ODBC) || defined(HAVE_MYSQL) alpar@1: alpar@1: #define SQL_FIELD_MAX 100 alpar@1: /* maximal field count */ alpar@1: alpar@1: #define SQL_FDLEN_MAX 255 alpar@1: /* maximal field length */ alpar@1: alpar@1: /*********************************************************************** alpar@1: * NAME alpar@1: * alpar@1: * args_concat - concatenate arguments alpar@1: * alpar@1: * SYNOPSIS alpar@1: * alpar@1: * static char **args_concat(TABDCA *dca); alpar@1: * alpar@1: * DESCRIPTION alpar@1: * alpar@1: * The arguments passed in dca are SQL statements. A SQL statement may alpar@1: * be split over multiple arguments. The last argument of a SQL alpar@1: * statement will be terminated with a semilocon. Each SQL statement is alpar@1: * merged into a single zero terminated string. Boundaries between alpar@1: * arguments are replaced by space. alpar@1: * alpar@1: * RETURNS alpar@1: * alpar@1: * Buffer with SQL statements */ alpar@1: alpar@1: static char **args_concat(TABDCA *dca) alpar@1: { alpar@1: const char *arg; alpar@1: int i; alpar@1: int j; alpar@1: int j0; alpar@1: int j1; alpar@1: int len; alpar@1: int lentot; alpar@1: int narg; alpar@1: int nline = 0; alpar@1: void *ret; alpar@1: char **sqllines = NULL; alpar@1: alpar@1: narg = mpl_tab_num_args(dca); alpar@1: /* The SQL statements start with argument 3. */ alpar@1: if (narg < 3) alpar@1: return NULL; alpar@1: /* Count the SQL statements */ alpar@1: for (j = 3; j <= narg; j++) alpar@1: { alpar@1: arg = mpl_tab_get_arg(dca, j); alpar@1: len = strlen(arg); alpar@1: if (arg[len-1] == ';' || j == narg) alpar@1: nline ++; alpar@1: } alpar@1: /* Allocate string buffer. */ alpar@1: sqllines = (char **) xmalloc((nline+1) * sizeof(char **)); alpar@1: /* Join arguments */ alpar@1: sqllines[0] = NULL; alpar@1: j0 = 3; alpar@1: i = 0; alpar@1: lentot = 0; alpar@1: for (j = 3; j <= narg; j++) alpar@1: { alpar@1: arg = mpl_tab_get_arg(dca, j); alpar@1: len = strlen(arg); alpar@1: lentot += len; alpar@1: if (arg[len-1] == ';' || j == narg) alpar@1: { /* Join arguments for a single SQL statement */ alpar@1: sqllines[i] = xmalloc(lentot+1); alpar@1: sqllines[i+1] = NULL; alpar@1: sqllines[i][0] = 0x00; alpar@1: for (j1 = j0; j1 <= j; j1++) alpar@1: { if(j1>j0) alpar@1: strcat(sqllines[i], " "); alpar@1: strcat(sqllines[i], mpl_tab_get_arg(dca, j1)); alpar@1: } alpar@1: len = strlen(sqllines[i]); alpar@1: if (sqllines[i][len-1] == ';') alpar@1: sqllines[i][len-1] = 0x00; alpar@1: j0 = j+1; alpar@1: i++; alpar@1: lentot = 0; alpar@1: } alpar@1: } alpar@1: return sqllines; alpar@1: } alpar@1: alpar@1: /*********************************************************************** alpar@1: * NAME alpar@1: * alpar@1: * free_buffer - free multiline string buffer alpar@1: * alpar@1: * SYNOPSIS alpar@1: * alpar@1: * static void free_buffer(char **buf); alpar@1: * alpar@1: * DESCRIPTION alpar@1: * alpar@1: * buf is a list of strings terminated by NULL. alpar@1: * The memory for the strings and for the list is released. */ alpar@1: alpar@1: static void free_buffer(char **buf) alpar@1: { int i; alpar@1: alpar@1: for(i = 0; buf[i] != NULL; i++) alpar@1: xfree(buf[i]); alpar@1: xfree(buf); alpar@1: } alpar@1: alpar@1: static int db_escaped_string_length(const char* from) alpar@1: /* length of escaped string */ alpar@1: { alpar@1: int count; alpar@1: const char *pointer; alpar@1: alpar@1: for (pointer = from, count = 0; *pointer != (char) '\0'; pointer++, alpar@1: count++) alpar@1: { alpar@1: switch (*pointer) alpar@1: { alpar@1: case '\'': alpar@1: count++; alpar@1: break; alpar@1: } alpar@1: } alpar@1: alpar@1: return count; alpar@1: } alpar@1: alpar@1: static int db_escape_string (char *to, const char *from) alpar@1: /* escape string*/ alpar@1: { alpar@1: const char *source = from; alpar@1: char *target = to; alpar@1: unsigned int remaining; alpar@1: alpar@1: remaining = strlen(from); alpar@1: alpar@1: if (to == NULL) alpar@1: to = (char *) (from + remaining); alpar@1: alpar@1: while (remaining > 0) alpar@1: { alpar@1: switch (*source) alpar@1: { alpar@1: case '\'': alpar@1: *target = '\''; alpar@1: target++; alpar@1: *target = '\''; alpar@1: break; alpar@1: alpar@1: default: alpar@1: *target = *source; alpar@1: } alpar@1: source++; alpar@1: target++; alpar@1: remaining--; alpar@1: } alpar@1: alpar@1: /* Write the terminating NUL character. */ alpar@1: *target = '\0'; alpar@1: alpar@1: return target - to; alpar@1: } alpar@1: alpar@1: static char *db_generate_select_stmt(TABDCA *dca) alpar@1: /* generate select statement */ alpar@1: { alpar@1: char *arg; alpar@1: char const *field; alpar@1: char *query; alpar@1: int j; alpar@1: int narg; alpar@1: int nf; alpar@1: int total; alpar@1: alpar@1: total = 50; alpar@1: nf = mpl_tab_num_flds(dca); alpar@1: narg = mpl_tab_num_args(dca); alpar@1: for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++) alpar@1: { alpar@1: field = mpl_tab_get_name(dca, j); alpar@1: total += strlen(field); alpar@1: total += 2; alpar@1: } alpar@1: arg = (char *) mpl_tab_get_arg(dca, narg); alpar@1: total += strlen(arg); alpar@1: query = xmalloc( total * sizeof(char)); alpar@1: strcpy (query, "SELECT "); alpar@1: for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++) alpar@1: { alpar@1: field = mpl_tab_get_name(dca, j); alpar@1: strcat(query, field); alpar@1: if ( j < nf ) alpar@1: strcat(query, ", "); alpar@1: } alpar@1: strcat(query, " FROM "); alpar@1: strcat(query, arg); alpar@1: return query; alpar@1: } alpar@1: alpar@1: static char *db_generate_insert_stmt(TABDCA *dca) alpar@1: /* generate insert statement */ alpar@1: { alpar@1: char *arg; alpar@1: char const *field; alpar@1: char *query; alpar@1: int j; alpar@1: int narg; alpar@1: int nf; alpar@1: int total; alpar@1: alpar@1: total = 50; alpar@1: nf = mpl_tab_num_flds(dca); alpar@1: narg = mpl_tab_num_args(dca); alpar@1: for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++) alpar@1: { alpar@1: field = mpl_tab_get_name(dca, j); alpar@1: total += strlen(field); alpar@1: total += 5; alpar@1: } alpar@1: arg = (char *) mpl_tab_get_arg(dca, narg); alpar@1: total += strlen(arg); alpar@1: query = xmalloc( (total+1) * sizeof(char)); alpar@1: strcpy (query, "INSERT INTO "); alpar@1: strcat(query, arg); alpar@1: strcat(query, " ( "); alpar@1: for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++) alpar@1: { alpar@1: field = mpl_tab_get_name(dca, j); alpar@1: strcat(query, field); alpar@1: if ( j < nf ) alpar@1: strcat(query, ", "); alpar@1: } alpar@1: strcat(query, " ) VALUES ( "); alpar@1: for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++) alpar@1: { alpar@1: strcat(query, "?"); alpar@1: if ( j < nf ) alpar@1: strcat(query, ", "); alpar@1: } alpar@1: strcat(query, " )"); alpar@1: return query; alpar@1: } alpar@1: alpar@1: #endif alpar@1: alpar@1: /**********************************************************************/ alpar@1: alpar@1: #ifndef HAVE_ODBC alpar@1: alpar@1: void *db_iodbc_open(TABDCA *dca, int mode) alpar@1: { xassert(dca == dca); alpar@1: xassert(mode == mode); alpar@1: xprintf("iODBC table driver not supported\n"); alpar@1: return NULL; alpar@1: } alpar@1: alpar@1: int db_iodbc_read(TABDCA *dca, void *link) alpar@1: { xassert(dca != dca); alpar@1: xassert(link != link); alpar@1: return 0; alpar@1: } alpar@1: alpar@1: int db_iodbc_write(TABDCA *dca, void *link) alpar@1: { xassert(dca != dca); alpar@1: xassert(link != link); alpar@1: return 0; alpar@1: } alpar@1: alpar@1: int db_iodbc_close(TABDCA *dca, void *link) alpar@1: { xassert(dca != dca); alpar@1: xassert(link != link); alpar@1: return 0; alpar@1: } alpar@1: alpar@1: #else alpar@1: alpar@1: #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__) alpar@1: #include alpar@1: #endif alpar@1: alpar@1: #include alpar@1: #include alpar@1: alpar@1: struct db_odbc alpar@1: { alpar@1: int mode; /*'R' = Read, 'W' = Write*/ alpar@1: SQLHDBC hdbc; /*connection handle*/ alpar@1: SQLHENV henv; /*environment handle*/ alpar@1: SQLHSTMT hstmt; /*statement handle*/ alpar@1: SQLSMALLINT nresultcols; /* columns in result*/ alpar@1: SQLULEN collen[SQL_FIELD_MAX+1]; alpar@1: SQLLEN outlen[SQL_FIELD_MAX+1]; alpar@1: SQLSMALLINT coltype[SQL_FIELD_MAX+1]; alpar@1: SQLCHAR data[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1]; alpar@1: SQLCHAR colname[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1]; alpar@1: int isnumeric[SQL_FIELD_MAX+1]; alpar@1: int nf; alpar@1: /* number of fields in the csv file */ alpar@1: int ref[1+SQL_FIELD_MAX]; alpar@1: /* ref[k] = k', if k-th field of the csv file corresponds to alpar@1: k'-th field in the table statement; if ref[k] = 0, k-th field alpar@1: of the csv file is ignored */ alpar@1: SQLCHAR *query; alpar@1: /* query generated by db_iodbc_open */ alpar@1: }; alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLAllocHandle ( alpar@1: SQLSMALLINT HandleType, alpar@1: SQLHANDLE InputHandle, alpar@1: SQLHANDLE *OutputHandle) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLAllocHandle( alpar@1: SQLSMALLINT HandleType, alpar@1: SQLHANDLE InputHandle, alpar@1: SQLHANDLE *OutputHandle); alpar@1: alpar@1: ep_SQLAllocHandle *fn; alpar@1: fn = (ep_SQLAllocHandle *) xdlsym(h_odbc, "SQLAllocHandle"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(HandleType, InputHandle, OutputHandle); alpar@1: } alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLBindCol ( alpar@1: SQLHSTMT StatementHandle, alpar@1: SQLUSMALLINT ColumnNumber, alpar@1: SQLSMALLINT TargetType, alpar@1: SQLPOINTER TargetValue, alpar@1: SQLLEN BufferLength, alpar@1: SQLLEN *StrLen_or_Ind) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLBindCol( alpar@1: SQLHSTMT StatementHandle, alpar@1: SQLUSMALLINT ColumnNumber, alpar@1: SQLSMALLINT TargetType, alpar@1: SQLPOINTER TargetValue, alpar@1: SQLLEN BufferLength, alpar@1: SQLLEN *StrLen_or_Ind); alpar@1: ep_SQLBindCol *fn; alpar@1: fn = (ep_SQLBindCol *) xdlsym(h_odbc, "SQLBindCol"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(StatementHandle, ColumnNumber, TargetType, alpar@1: TargetValue, BufferLength, StrLen_or_Ind); alpar@1: } alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLCloseCursor ( alpar@1: SQLHSTMT StatementHandle) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLCloseCursor ( alpar@1: SQLHSTMT StatementHandle); alpar@1: alpar@1: ep_SQLCloseCursor *fn; alpar@1: fn = (ep_SQLCloseCursor *) xdlsym(h_odbc, "SQLCloseCursor"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(StatementHandle); alpar@1: } alpar@1: alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLDisconnect ( alpar@1: SQLHDBC ConnectionHandle) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLDisconnect( alpar@1: SQLHDBC ConnectionHandle); alpar@1: alpar@1: ep_SQLDisconnect *fn; alpar@1: fn = (ep_SQLDisconnect *) xdlsym(h_odbc, "SQLDisconnect"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(ConnectionHandle); alpar@1: } alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLDriverConnect ( alpar@1: SQLHDBC hdbc, alpar@1: SQLHWND hwnd, alpar@1: SQLCHAR *szConnStrIn, alpar@1: SQLSMALLINT cbConnStrIn, alpar@1: SQLCHAR *szConnStrOut, alpar@1: SQLSMALLINT cbConnStrOutMax, alpar@1: SQLSMALLINT *pcbConnStrOut, alpar@1: SQLUSMALLINT fDriverCompletion) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLDriverConnect( alpar@1: SQLHDBC hdbc, alpar@1: SQLHWND hwnd, alpar@1: SQLCHAR * szConnStrIn, alpar@1: SQLSMALLINT cbConnStrIn, alpar@1: SQLCHAR * szConnStrOut, alpar@1: SQLSMALLINT cbConnStrOutMax, alpar@1: SQLSMALLINT * pcbConnStrOut, alpar@1: SQLUSMALLINT fDriverCompletion); alpar@1: alpar@1: ep_SQLDriverConnect *fn; alpar@1: fn = (ep_SQLDriverConnect *) xdlsym(h_odbc, "SQLDriverConnect"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut, alpar@1: cbConnStrOutMax, pcbConnStrOut, fDriverCompletion); alpar@1: } alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLEndTran ( alpar@1: SQLSMALLINT HandleType, alpar@1: SQLHANDLE Handle, alpar@1: SQLSMALLINT CompletionType) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLEndTran ( alpar@1: SQLSMALLINT HandleType, alpar@1: SQLHANDLE Handle, alpar@1: SQLSMALLINT CompletionType); alpar@1: alpar@1: ep_SQLEndTran *fn; alpar@1: fn = (ep_SQLEndTran *) xdlsym(h_odbc, "SQLEndTran"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(HandleType, Handle, CompletionType); alpar@1: } alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLExecDirect ( alpar@1: SQLHSTMT StatementHandle, alpar@1: SQLCHAR * StatementText, alpar@1: SQLINTEGER TextLength) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLExecDirect ( alpar@1: SQLHSTMT StatementHandle, alpar@1: SQLCHAR * StatementText, alpar@1: SQLINTEGER TextLength); alpar@1: alpar@1: ep_SQLExecDirect *fn; alpar@1: fn = (ep_SQLExecDirect *) xdlsym(h_odbc, "SQLExecDirect"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(StatementHandle, StatementText, TextLength); alpar@1: } alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLFetch ( alpar@1: SQLHSTMT StatementHandle) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLFetch ( alpar@1: SQLHSTMT StatementHandle); alpar@1: alpar@1: ep_SQLFetch *fn; alpar@1: fn = (ep_SQLFetch*) xdlsym(h_odbc, "SQLFetch"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(StatementHandle); alpar@1: } alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLFreeHandle ( alpar@1: SQLSMALLINT HandleType, alpar@1: SQLHANDLE Handle) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLFreeHandle ( alpar@1: SQLSMALLINT HandleType, alpar@1: SQLHANDLE Handle); alpar@1: alpar@1: ep_SQLFreeHandle *fn; alpar@1: fn = (ep_SQLFreeHandle *) xdlsym(h_odbc, "SQLFreeHandle"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(HandleType, Handle); alpar@1: } alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLDescribeCol ( alpar@1: SQLHSTMT StatementHandle, alpar@1: SQLUSMALLINT ColumnNumber, alpar@1: SQLCHAR * ColumnName, alpar@1: SQLSMALLINT BufferLength, alpar@1: SQLSMALLINT * NameLength, alpar@1: SQLSMALLINT * DataType, alpar@1: SQLULEN * ColumnSize, alpar@1: SQLSMALLINT * DecimalDigits, alpar@1: SQLSMALLINT * Nullable) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLDescribeCol ( alpar@1: SQLHSTMT StatementHandle, alpar@1: SQLUSMALLINT ColumnNumber, alpar@1: SQLCHAR *ColumnName, alpar@1: SQLSMALLINT BufferLength, alpar@1: SQLSMALLINT *NameLength, alpar@1: SQLSMALLINT *DataType, alpar@1: SQLULEN *ColumnSize, alpar@1: SQLSMALLINT *DecimalDigits, alpar@1: SQLSMALLINT *Nullable); alpar@1: alpar@1: ep_SQLDescribeCol *fn; alpar@1: fn = (ep_SQLDescribeCol *) xdlsym(h_odbc, "SQLDescribeCol"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(StatementHandle, ColumnNumber, ColumnName, alpar@1: BufferLength, NameLength, alpar@1: DataType, ColumnSize, DecimalDigits, Nullable); alpar@1: } alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLGetDiagRec ( alpar@1: SQLSMALLINT HandleType, alpar@1: SQLHANDLE Handle, alpar@1: SQLSMALLINT RecNumber, alpar@1: SQLCHAR *Sqlstate, alpar@1: SQLINTEGER *NativeError, alpar@1: SQLCHAR *MessageText, alpar@1: SQLSMALLINT BufferLength, alpar@1: SQLSMALLINT *TextLength) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLGetDiagRec ( alpar@1: SQLSMALLINT HandleType, alpar@1: SQLHANDLE Handle, alpar@1: SQLSMALLINT RecNumber, alpar@1: SQLCHAR *Sqlstate, alpar@1: SQLINTEGER *NativeError, alpar@1: SQLCHAR *MessageText, alpar@1: SQLSMALLINT BufferLength, alpar@1: SQLSMALLINT *TextLength); alpar@1: alpar@1: ep_SQLGetDiagRec *fn; alpar@1: fn = (ep_SQLGetDiagRec *) xdlsym(h_odbc, "SQLGetDiagRec"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(HandleType, Handle, RecNumber, Sqlstate, alpar@1: NativeError, MessageText, BufferLength, TextLength); alpar@1: } alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLGetInfo ( alpar@1: SQLHDBC ConnectionHandle, alpar@1: SQLUSMALLINT InfoType, alpar@1: SQLPOINTER InfoValue, alpar@1: SQLSMALLINT BufferLength, alpar@1: SQLSMALLINT *StringLength) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLGetInfo ( alpar@1: SQLHDBC ConnectionHandle, alpar@1: SQLUSMALLINT InfoType, alpar@1: SQLPOINTER InfoValue, alpar@1: SQLSMALLINT BufferLength, alpar@1: SQLSMALLINT *StringLength); alpar@1: alpar@1: ep_SQLGetInfo *fn; alpar@1: fn = (ep_SQLGetInfo *) xdlsym(h_odbc, "SQLGetInfo"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(ConnectionHandle, InfoType, InfoValue, BufferLength, alpar@1: StringLength); alpar@1: } alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLNumResultCols ( alpar@1: SQLHSTMT StatementHandle, alpar@1: SQLSMALLINT *ColumnCount) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLNumResultCols ( alpar@1: SQLHSTMT StatementHandle, alpar@1: SQLSMALLINT *ColumnCount); alpar@1: alpar@1: ep_SQLNumResultCols *fn; alpar@1: fn = (ep_SQLNumResultCols *) xdlsym(h_odbc, "SQLNumResultCols"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(StatementHandle, ColumnCount); alpar@1: } alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLSetConnectAttr ( alpar@1: SQLHDBC ConnectionHandle, alpar@1: SQLINTEGER Attribute, alpar@1: SQLPOINTER Value, alpar@1: SQLINTEGER StringLength) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLSetConnectAttr ( alpar@1: SQLHDBC ConnectionHandle, alpar@1: SQLINTEGER Attribute, alpar@1: SQLPOINTER Value, alpar@1: SQLINTEGER StringLength); alpar@1: alpar@1: ep_SQLSetConnectAttr *fn; alpar@1: fn = (ep_SQLSetConnectAttr *) xdlsym(h_odbc, "SQLSetConnectAttr"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(ConnectionHandle, Attribute, Value, StringLength); alpar@1: } alpar@1: alpar@1: SQLRETURN SQL_API dl_SQLSetEnvAttr ( alpar@1: SQLHENV EnvironmentHandle, alpar@1: SQLINTEGER Attribute, alpar@1: SQLPOINTER Value, alpar@1: SQLINTEGER StringLength) alpar@1: { alpar@1: typedef SQLRETURN SQL_API ep_SQLSetEnvAttr ( alpar@1: SQLHENV EnvironmentHandle, alpar@1: SQLINTEGER Attribute, alpar@1: SQLPOINTER Value, alpar@1: SQLINTEGER StringLength); alpar@1: alpar@1: ep_SQLSetEnvAttr *fn; alpar@1: fn = (ep_SQLSetEnvAttr *) xdlsym(h_odbc, "SQLSetEnvAttr"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(EnvironmentHandle, Attribute, Value, StringLength); alpar@1: } alpar@1: alpar@1: static void extract_error( alpar@1: char *fn, alpar@1: SQLHANDLE handle, alpar@1: SQLSMALLINT type); alpar@1: alpar@1: static int is_numeric( alpar@1: SQLSMALLINT coltype); alpar@1: alpar@1: /*********************************************************************** alpar@1: * NAME alpar@1: * alpar@1: * db_iodbc_open - open connection to ODBC data base alpar@1: * alpar@1: * SYNOPSIS alpar@1: * alpar@1: * #include "glpsql.h" alpar@1: * void *db_iodbc_open(TABDCA *dca, int mode); alpar@1: * alpar@1: * DESCRIPTION alpar@1: * alpar@1: * The routine db_iodbc_open opens a connection to an ODBC data base. alpar@1: * It then executes the sql statements passed. alpar@1: * alpar@1: * In the case of table read the SELECT statement is executed. alpar@1: * alpar@1: * In the case of table write the INSERT statement is prepared. alpar@1: * RETURNS alpar@1: * alpar@1: * The routine returns a pointer to data storage area created. */ alpar@1: void *db_iodbc_open(TABDCA *dca, int mode) alpar@1: { void *ret; alpar@1: char **sqllines; alpar@1: alpar@1: sqllines = args_concat(dca); alpar@1: if (sqllines == NULL) alpar@1: { xprintf("Missing arguments in table statement.\n" alpar@1: "Please, supply table driver, dsn, and query.\n"); alpar@1: return NULL; alpar@1: } alpar@1: ret = db_iodbc_open_int(dca, mode, (const char **) sqllines); alpar@1: free_buffer(sqllines); alpar@1: return ret; alpar@1: } alpar@1: alpar@1: static void *db_iodbc_open_int(TABDCA *dca, int mode, const char alpar@1: **sqllines) alpar@1: { alpar@1: struct db_odbc *sql; alpar@1: SQLRETURN ret; alpar@1: SQLCHAR FAR *dsn; alpar@1: SQLCHAR info[256]; alpar@1: SQLSMALLINT colnamelen; alpar@1: SQLSMALLINT nullable; alpar@1: SQLSMALLINT scale; alpar@1: const char *arg; alpar@1: int narg; alpar@1: int i, j; alpar@1: int total; alpar@1: alpar@1: if (libodbc == NULL) alpar@1: { alpar@1: xprintf("No loader for shared ODBC library available\n"); alpar@1: return NULL; alpar@1: } alpar@1: alpar@1: if (h_odbc == NULL) alpar@1: { alpar@1: h_odbc = xdlopen(libodbc); alpar@1: if (h_odbc == NULL) alpar@1: { xprintf("unable to open library %s\n", libodbc); alpar@1: xprintf("%s\n", xerrmsg()); alpar@1: return NULL; alpar@1: } alpar@1: } alpar@1: alpar@1: sql = (struct db_odbc *) xmalloc(sizeof(struct db_odbc)); alpar@1: if (sql == NULL) alpar@1: return NULL; alpar@1: alpar@1: sql->mode = mode; alpar@1: sql->hdbc = NULL; alpar@1: sql->henv = NULL; alpar@1: sql->hstmt = NULL; alpar@1: sql->query = NULL; alpar@1: narg = mpl_tab_num_args(dca); alpar@1: alpar@1: dsn = (SQLCHAR FAR *) mpl_tab_get_arg(dca, 2); alpar@1: /* allocate an environment handle */ alpar@1: ret = dl_SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, alpar@1: &(sql->henv)); alpar@1: /* set attribute to enable application to run as ODBC 3.0 alpar@1: application */ alpar@1: ret = dl_SQLSetEnvAttr(sql->henv, SQL_ATTR_ODBC_VERSION, alpar@1: (void *) SQL_OV_ODBC3, 0); alpar@1: /* allocate a connection handle */ alpar@1: ret = dl_SQLAllocHandle(SQL_HANDLE_DBC, sql->henv, &(sql->hdbc)); alpar@1: /* connect */ alpar@1: ret = dl_SQLDriverConnect(sql->hdbc, NULL, dsn, SQL_NTS, NULL, 0, alpar@1: NULL, SQL_DRIVER_COMPLETE); alpar@1: if (SQL_SUCCEEDED(ret)) alpar@1: { /* output information about data base connection */ alpar@1: xprintf("Connected to "); alpar@1: dl_SQLGetInfo(sql->hdbc, SQL_DBMS_NAME, (SQLPOINTER)info, alpar@1: sizeof(info), NULL); alpar@1: xprintf("%s ", info); alpar@1: dl_SQLGetInfo(sql->hdbc, SQL_DBMS_VER, (SQLPOINTER)info, alpar@1: sizeof(info), NULL); alpar@1: xprintf("%s - ", info); alpar@1: dl_SQLGetInfo(sql->hdbc, SQL_DATABASE_NAME, (SQLPOINTER)info, alpar@1: sizeof(info), NULL); alpar@1: xprintf("%s\n", info); alpar@1: } alpar@1: else alpar@1: { /* describe error */ alpar@1: xprintf("Failed to connect\n"); alpar@1: extract_error("SQLDriverConnect", sql->hdbc, SQL_HANDLE_DBC); alpar@1: dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc); alpar@1: dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv); alpar@1: xfree(sql); alpar@1: return NULL; alpar@1: } alpar@1: /* set AUTOCOMMIT on*/ alpar@1: ret = dl_SQLSetConnectAttr(sql->hdbc, SQL_ATTR_AUTOCOMMIT, alpar@1: (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0); alpar@1: /* allocate a statement handle */ alpar@1: ret = dl_SQLAllocHandle(SQL_HANDLE_STMT, sql->hdbc, &(sql->hstmt)); alpar@1: alpar@1: /* initialization queries */ alpar@1: for(j = 0; sqllines[j+1] != NULL; j++) alpar@1: { alpar@1: sql->query = (SQLCHAR *) sqllines[j]; alpar@1: xprintf("%s\n", sql->query); alpar@1: ret = dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS); alpar@1: switch (ret) alpar@1: { alpar@1: case SQL_SUCCESS: alpar@1: case SQL_SUCCESS_WITH_INFO: alpar@1: case SQL_NO_DATA_FOUND: alpar@1: break; alpar@1: default: alpar@1: xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n", alpar@1: sql->query); alpar@1: extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT); alpar@1: dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt); alpar@1: dl_SQLDisconnect(sql->hdbc); alpar@1: dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc); alpar@1: dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv); alpar@1: xfree(sql); alpar@1: return NULL; alpar@1: } alpar@1: /* commit statement */ alpar@1: dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT); alpar@1: } alpar@1: alpar@1: if ( sql->mode == 'R' ) alpar@1: { sql->nf = mpl_tab_num_flds(dca); alpar@1: for(j = 0; sqllines[j] != NULL; j++) alpar@1: arg = sqllines[j]; alpar@1: total = strlen(arg); alpar@1: if (total > 7 && 0 == strncmp(arg, "SELECT ", 7)) alpar@1: { alpar@1: total = strlen(arg); alpar@1: sql->query = xmalloc( (total+1) * sizeof(char)); alpar@1: strcpy (sql->query, arg); alpar@1: } alpar@1: else alpar@1: { alpar@1: sql->query = db_generate_select_stmt(dca); alpar@1: } alpar@1: xprintf("%s\n", sql->query); alpar@1: if (dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS) != alpar@1: SQL_SUCCESS) alpar@1: { alpar@1: xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n", sql->query); alpar@1: extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT); alpar@1: dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt); alpar@1: dl_SQLDisconnect(sql->hdbc); alpar@1: dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc); alpar@1: dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv); alpar@1: xfree(sql->query); alpar@1: xfree(sql); alpar@1: return NULL; alpar@1: } alpar@1: xfree(sql->query); alpar@1: /* determine number of result columns */ alpar@1: ret = dl_SQLNumResultCols(sql->hstmt, &sql->nresultcols); alpar@1: total = sql->nresultcols; alpar@1: if (total > SQL_FIELD_MAX) alpar@1: { xprintf("db_iodbc_open: Too many fields (> %d) in query.\n" alpar@1: "\"%s\"\n", SQL_FIELD_MAX, sql->query); alpar@1: dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt); alpar@1: dl_SQLDisconnect(sql->hdbc); alpar@1: dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc); alpar@1: dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv); alpar@1: xfree(sql->query); alpar@1: return NULL; alpar@1: } alpar@1: for (i = 1; i <= total; i++) alpar@1: { /* return a set of attributes for a column */ alpar@1: ret = dl_SQLDescribeCol(sql->hstmt, (SQLSMALLINT) i, alpar@1: sql->colname[i], SQL_FDLEN_MAX, alpar@1: &colnamelen, &(sql->coltype[i]), &(sql->collen[i]), &scale, alpar@1: &nullable); alpar@1: sql->isnumeric[i] = is_numeric(sql->coltype[i]); alpar@1: /* bind columns to program vars, converting all types to CHAR*/ alpar@1: dl_SQLBindCol(sql->hstmt, i, SQL_CHAR, sql->data[i], alpar@1: SQL_FDLEN_MAX, &(sql->outlen[i])); alpar@1: for (j = sql->nf; j >= 1; j--) alpar@1: { if (strcmp(mpl_tab_get_name(dca, j), sql->colname[i]) == 0) alpar@1: break; alpar@1: } alpar@1: sql->ref[i] = j; alpar@1: } alpar@1: } alpar@1: else if ( sql->mode == 'W' ) alpar@1: { for(j = 0; sqllines[j] != NULL; j++) alpar@1: arg = sqllines[j]; alpar@1: if ( NULL != strchr(arg, '?') ) alpar@1: { alpar@1: total = strlen(arg); alpar@1: sql->query = xmalloc( (total+1) * sizeof(char)); alpar@1: strcpy (sql->query, arg); alpar@1: } alpar@1: else alpar@1: { alpar@1: sql->query = db_generate_insert_stmt(dca); alpar@1: } alpar@1: xprintf("%s\n", sql->query); alpar@1: } alpar@1: return sql; alpar@1: } alpar@1: alpar@1: int db_iodbc_read(TABDCA *dca, void *link) alpar@1: { alpar@1: struct db_odbc *sql; alpar@1: SQLRETURN ret; alpar@1: char buf[SQL_FDLEN_MAX+1]; alpar@1: int i; alpar@1: int len; alpar@1: double num; alpar@1: alpar@1: sql = (struct db_odbc *) link; alpar@1: alpar@1: xassert(sql != NULL); alpar@1: xassert(sql->mode == 'R'); alpar@1: alpar@1: ret=dl_SQLFetch(sql->hstmt); alpar@1: if (ret== SQL_ERROR) alpar@1: return -1; alpar@1: if (ret== SQL_NO_DATA_FOUND) alpar@1: return -1; /*EOF*/ alpar@1: for (i=1; i <= sql->nresultcols; i++) alpar@1: { alpar@1: if (sql->ref[i] > 0) alpar@1: { alpar@1: len = sql->outlen[i]; alpar@1: if (len != SQL_NULL_DATA) alpar@1: { alpar@1: if (len > SQL_FDLEN_MAX) alpar@1: len = SQL_FDLEN_MAX; alpar@1: else if (len < 0) alpar@1: len = 0; alpar@1: strncpy(buf, (const char *) sql->data[i], len); alpar@1: buf[len] = 0x00; alpar@1: if (0 != (sql->isnumeric[i])) alpar@1: { strspx(buf); /* remove spaces*/ alpar@1: if (str2num(buf, &num) != 0) alpar@1: { xprintf("'%s' cannot be converted to a number.\n", alpar@1: buf); alpar@1: return 1; alpar@1: } alpar@1: mpl_tab_set_num(dca, sql->ref[i], num); alpar@1: } alpar@1: else alpar@1: { mpl_tab_set_str(dca, sql->ref[i], strtrim(buf)); alpar@1: } alpar@1: } alpar@1: } alpar@1: } alpar@1: return 0; alpar@1: } alpar@1: alpar@1: int db_iodbc_write(TABDCA *dca, void *link) alpar@1: { alpar@1: struct db_odbc *sql; alpar@1: char *part; alpar@1: char *query; alpar@1: char *template; alpar@1: char num[50]; alpar@1: int k; alpar@1: int len; alpar@1: int nf; alpar@1: alpar@1: sql = (struct db_odbc *) link; alpar@1: xassert(sql != NULL); alpar@1: xassert(sql->mode == 'W'); alpar@1: alpar@1: len = strlen(sql->query); alpar@1: template = (char *) xmalloc( (len + 1) * sizeof(char) ); alpar@1: strcpy(template, sql->query); alpar@1: alpar@1: nf = mpl_tab_num_flds(dca); alpar@1: for (k = 1; k <= nf; k++) alpar@1: { switch (mpl_tab_get_type(dca, k)) alpar@1: { case 'N': alpar@1: len += 20; alpar@1: break; alpar@1: case 'S': alpar@1: len += db_escaped_string_length(mpl_tab_get_str(dca, k)); alpar@1: len += 2; alpar@1: break; alpar@1: default: alpar@1: xassert(dca != dca); alpar@1: } alpar@1: } alpar@1: query = xmalloc( (len + 1 ) * sizeof(char) ); alpar@1: query[0] = 0x00; alpar@1: for (k = 1, part = strtok (template, "?"); (part != NULL); alpar@1: part = strtok (NULL, "?"), k++) alpar@1: { alpar@1: if (k > nf) break; alpar@1: strcat( query, part ); alpar@1: switch (mpl_tab_get_type(dca, k)) alpar@1: { case 'N': alpar@1: #if 0 /* 02/XI-2010 by xypron */ alpar@1: sprintf(num, "%-18g",mpl_tab_get_num(dca, k)); alpar@1: #else alpar@1: sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k)); alpar@1: #endif alpar@1: strcat( query, num ); alpar@1: break; alpar@1: case 'S': alpar@1: strcat( query, "'"); alpar@1: db_escape_string( query + strlen(query), alpar@1: mpl_tab_get_str(dca, k) ); alpar@1: strcat( query, "'"); alpar@1: break; alpar@1: default: alpar@1: xassert(dca != dca); alpar@1: } alpar@1: } alpar@1: if (part != NULL) alpar@1: strcat(query, part); alpar@1: if (dl_SQLExecDirect(sql->hstmt, (SQLCHAR *) query, SQL_NTS) alpar@1: != SQL_SUCCESS) alpar@1: { alpar@1: xprintf("db_iodbc_write: Query\n\"%s\"\nfailed.\n", query); alpar@1: extract_error("SQLExecDirect", sql->hdbc, SQL_HANDLE_DBC); alpar@1: xfree(query); alpar@1: xfree(template); alpar@1: return 1; alpar@1: } alpar@1: alpar@1: xfree(query); alpar@1: xfree(template); alpar@1: return 0; alpar@1: } alpar@1: alpar@1: int db_iodbc_close(TABDCA *dca, void *link) alpar@1: { alpar@1: struct db_odbc *sql; alpar@1: alpar@1: sql = (struct db_odbc *) link; alpar@1: xassert(sql != NULL); alpar@1: /* Commit */ alpar@1: if ( sql->mode == 'W' ) alpar@1: dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT); alpar@1: if ( sql->mode == 'R' ) alpar@1: dl_SQLCloseCursor(sql->hstmt); alpar@1: alpar@1: dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt); alpar@1: dl_SQLDisconnect(sql->hdbc); alpar@1: dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc); alpar@1: dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv); alpar@1: if ( sql->mode == 'W' ) alpar@1: xfree(sql->query); alpar@1: xfree(sql); alpar@1: dca->link = NULL; alpar@1: return 0; alpar@1: } alpar@1: alpar@1: static void extract_error( alpar@1: char *fn, alpar@1: SQLHANDLE handle, alpar@1: SQLSMALLINT type) alpar@1: { alpar@1: SQLINTEGER i = 0; alpar@1: SQLINTEGER native; alpar@1: SQLCHAR state[ 7 ]; alpar@1: SQLCHAR text[256]; alpar@1: SQLSMALLINT len; alpar@1: SQLRETURN ret; alpar@1: alpar@1: xprintf("\nThe driver reported the following diagnostics whilst " alpar@1: "running %s\n", fn); alpar@1: alpar@1: do alpar@1: { alpar@1: ret = dl_SQLGetDiagRec(type, handle, ++i, state, &native, text, alpar@1: sizeof(text), &len ); alpar@1: if (SQL_SUCCEEDED(ret)) alpar@1: xprintf("%s:%ld:%ld:%s\n", state, i, native, text); alpar@1: } alpar@1: while( ret == SQL_SUCCESS ); alpar@1: } alpar@1: alpar@1: static int is_numeric(SQLSMALLINT coltype) alpar@1: { alpar@1: int ret = 0; alpar@1: switch (coltype) alpar@1: { alpar@1: case SQL_DECIMAL: alpar@1: case SQL_NUMERIC: alpar@1: case SQL_SMALLINT: alpar@1: case SQL_INTEGER: alpar@1: case SQL_REAL: alpar@1: case SQL_FLOAT: alpar@1: case SQL_DOUBLE: alpar@1: case SQL_TINYINT: alpar@1: case SQL_BIGINT: alpar@1: ret = 1; alpar@1: break; alpar@1: } alpar@1: return ret; alpar@1: } alpar@1: alpar@1: #endif alpar@1: alpar@1: /**********************************************************************/ alpar@1: alpar@1: #ifndef HAVE_MYSQL alpar@1: alpar@1: void *db_mysql_open(TABDCA *dca, int mode) alpar@1: { xassert(dca == dca); alpar@1: xassert(mode == mode); alpar@1: xprintf("MySQL table driver not supported\n"); alpar@1: return NULL; alpar@1: } alpar@1: alpar@1: int db_mysql_read(TABDCA *dca, void *link) alpar@1: { xassert(dca != dca); alpar@1: xassert(link != link); alpar@1: return 0; alpar@1: } alpar@1: alpar@1: int db_mysql_write(TABDCA *dca, void *link) alpar@1: { xassert(dca != dca); alpar@1: xassert(link != link); alpar@1: return 0; alpar@1: } alpar@1: alpar@1: int db_mysql_close(TABDCA *dca, void *link) alpar@1: { xassert(dca != dca); alpar@1: xassert(link != link); alpar@1: return 0; alpar@1: } alpar@1: alpar@1: #else alpar@1: alpar@1: #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__) alpar@1: #include alpar@1: #endif alpar@1: alpar@1: #ifdef __CYGWIN__ alpar@1: #define byte_defined 1 alpar@1: #endif alpar@1: alpar@1: #include alpar@1: #include alpar@1: #include alpar@1: alpar@1: struct db_mysql alpar@1: { alpar@1: int mode; /*'R' = Read, 'W' = Write*/ alpar@1: MYSQL *con; /*connection*/ alpar@1: MYSQL_RES *res; /*result*/ alpar@1: int nf; alpar@1: /* number of fields in the csv file */ alpar@1: int ref[1+SQL_FIELD_MAX]; alpar@1: /* ref[k] = k', if k-th field of the csv file corresponds to alpar@1: k'-th field in the table statement; if ref[k] = 0, k-th field alpar@1: of the csv file is ignored */ alpar@1: char *query; alpar@1: /* query generated by db_mysql_open */ alpar@1: }; alpar@1: alpar@1: void STDCALL dl_mysql_close(MYSQL *sock) alpar@1: { alpar@1: typedef void STDCALL ep_mysql_close(MYSQL *sock); alpar@1: alpar@1: ep_mysql_close *fn; alpar@1: fn = (ep_mysql_close *) xdlsym(h_mysql, "mysql_close"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(sock); alpar@1: } alpar@1: alpar@1: const char * STDCALL dl_mysql_error(MYSQL *mysql) alpar@1: { alpar@1: typedef const char * STDCALL ep_mysql_error(MYSQL *mysql); alpar@1: alpar@1: ep_mysql_error *fn; alpar@1: fn = (ep_mysql_error *) xdlsym(h_mysql, "mysql_error"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(mysql); alpar@1: } alpar@1: alpar@1: MYSQL_FIELD * STDCALL dl_mysql_fetch_fields(MYSQL_RES *res) alpar@1: { alpar@1: typedef MYSQL_FIELD * STDCALL alpar@1: ep_mysql_fetch_fields(MYSQL_RES *res); alpar@1: alpar@1: ep_mysql_fetch_fields *fn; alpar@1: fn = (ep_mysql_fetch_fields *) xdlsym(h_mysql, "mysql_fetch_fields"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(res); alpar@1: } alpar@1: alpar@1: unsigned long * STDCALL dl_mysql_fetch_lengths(MYSQL_RES *result) alpar@1: { alpar@1: typedef unsigned long * STDCALL alpar@1: ep_mysql_fetch_lengths(MYSQL_RES *result); alpar@1: alpar@1: ep_mysql_fetch_lengths *fn; alpar@1: fn = (ep_mysql_fetch_lengths *) xdlsym(h_mysql, alpar@1: "mysql_fetch_lengths"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(result); alpar@1: } alpar@1: alpar@1: MYSQL_ROW STDCALL dl_mysql_fetch_row(MYSQL_RES *result) alpar@1: { alpar@1: typedef MYSQL_ROW STDCALL ep_mysql_fetch_row(MYSQL_RES *result); alpar@1: alpar@1: ep_mysql_fetch_row *fn; alpar@1: fn = (ep_mysql_fetch_row *) xdlsym(h_mysql, "mysql_fetch_row"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(result); alpar@1: } alpar@1: alpar@1: unsigned int STDCALL dl_mysql_field_count(MYSQL *mysql) alpar@1: { alpar@1: typedef unsigned int STDCALL ep_mysql_field_count(MYSQL *mysql); alpar@1: alpar@1: ep_mysql_field_count *fn; alpar@1: fn = (ep_mysql_field_count *) xdlsym(h_mysql, "mysql_field_count"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(mysql); alpar@1: } alpar@1: alpar@1: MYSQL * STDCALL dl_mysql_init(MYSQL *mysql) alpar@1: { alpar@1: typedef MYSQL * STDCALL ep_mysql_init(MYSQL *mysql); alpar@1: alpar@1: ep_mysql_init *fn; alpar@1: fn = (ep_mysql_init *) xdlsym(h_mysql, "mysql_init"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(mysql); alpar@1: } alpar@1: alpar@1: unsigned int STDCALL dl_mysql_num_fields(MYSQL_RES *res) alpar@1: { alpar@1: typedef unsigned int STDCALL ep_mysql_num_fields(MYSQL_RES *res); alpar@1: alpar@1: ep_mysql_num_fields *fn; alpar@1: fn = (ep_mysql_num_fields *) xdlsym(h_mysql, "mysql_num_fields"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(res); alpar@1: } alpar@1: alpar@1: int STDCALL dl_mysql_query(MYSQL *mysql, const char *q) alpar@1: { alpar@1: typedef int STDCALL ep_mysql_query(MYSQL *mysql, const char *q); alpar@1: alpar@1: ep_mysql_query *fn; alpar@1: fn = (ep_mysql_query *) xdlsym(h_mysql, "mysql_query"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(mysql, q); alpar@1: } alpar@1: alpar@1: MYSQL * STDCALL dl_mysql_real_connect(MYSQL *mysql, const char *host, alpar@1: const char *user, alpar@1: const char *passwd, alpar@1: const char *db, alpar@1: unsigned int port, alpar@1: const char *unix_socket, alpar@1: unsigned long clientflag) alpar@1: { alpar@1: typedef MYSQL * STDCALL ep_mysql_real_connect(MYSQL *mysql, alpar@1: const char *host, alpar@1: const char *user, alpar@1: const char *passwd, alpar@1: const char *db, alpar@1: unsigned int port, alpar@1: const char *unix_socket, alpar@1: unsigned long clientflag); alpar@1: alpar@1: ep_mysql_real_connect *fn; alpar@1: fn = (ep_mysql_real_connect *) xdlsym(h_mysql, alpar@1: "mysql_real_connect"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(mysql, host, user, passwd, db, port, unix_socket, alpar@1: clientflag); alpar@1: } alpar@1: alpar@1: MYSQL_RES * STDCALL dl_mysql_use_result(MYSQL *mysql) alpar@1: { alpar@1: typedef MYSQL_RES * STDCALL ep_mysql_use_result(MYSQL *mysql); alpar@1: ep_mysql_use_result *fn; alpar@1: fn = (ep_mysql_use_result *) xdlsym(h_mysql, "mysql_use_result"); alpar@1: xassert(fn != NULL); alpar@1: return (*fn)(mysql); alpar@1: } alpar@1: alpar@1: /*********************************************************************** alpar@1: * NAME alpar@1: * alpar@1: * db_mysql_open - open connection to ODBC data base alpar@1: * alpar@1: * SYNOPSIS alpar@1: * alpar@1: * #include "glpsql.h" alpar@1: * void *db_mysql_open(TABDCA *dca, int mode); alpar@1: * alpar@1: * DESCRIPTION alpar@1: * alpar@1: * The routine db_mysql_open opens a connection to a MySQL data base. alpar@1: * It then executes the sql statements passed. alpar@1: * alpar@1: * In the case of table read the SELECT statement is executed. alpar@1: * alpar@1: * In the case of table write the INSERT statement is prepared. alpar@1: * RETURNS alpar@1: * alpar@1: * The routine returns a pointer to data storage area created. */ alpar@1: alpar@1: void *db_mysql_open(TABDCA *dca, int mode) alpar@1: { void *ret; alpar@1: char **sqllines; alpar@1: alpar@1: sqllines = args_concat(dca); alpar@1: if (sqllines == NULL) alpar@1: { xprintf("Missing arguments in table statement.\n" alpar@1: "Please, supply table driver, dsn, and query.\n"); alpar@1: return NULL; alpar@1: } alpar@1: ret = db_mysql_open_int(dca, mode, (const char **) sqllines); alpar@1: free_buffer(sqllines); alpar@1: return ret; alpar@1: } alpar@1: alpar@1: static void *db_mysql_open_int(TABDCA *dca, int mode, const char alpar@1: **sqllines) alpar@1: { alpar@1: struct db_mysql *sql = NULL; alpar@1: char *arg = NULL; alpar@1: const char *field; alpar@1: MYSQL_FIELD *fields; alpar@1: char *keyword; alpar@1: char *value; alpar@1: char *query; alpar@1: char *dsn; alpar@1: /* "Server=[server_name];Database=[database_name];UID=[username];*/ alpar@1: /* PWD=[password];Port=[port]"*/ alpar@1: char *server = NULL; /* Server */ alpar@1: char *user = NULL; /* UID */ alpar@1: char *password = NULL; /* PWD */ alpar@1: char *database = NULL; /* Database */ alpar@1: unsigned int port = 0; /* Port */ alpar@1: int narg; alpar@1: int i, j, total; alpar@1: alpar@1: if (libmysql == NULL) alpar@1: { alpar@1: xprintf("No loader for shared MySQL library available\n"); alpar@1: return NULL; alpar@1: } alpar@1: alpar@1: if (h_mysql == NULL) alpar@1: { alpar@1: h_mysql = xdlopen(libmysql); alpar@1: if (h_mysql == NULL) alpar@1: { xprintf("unable to open library %s\n", libmysql); alpar@1: xprintf("%s\n", xerrmsg()); alpar@1: return NULL; alpar@1: } alpar@1: } alpar@1: alpar@1: sql = (struct db_mysql *) xmalloc(sizeof(struct db_mysql)); alpar@1: if (sql == NULL) alpar@1: return NULL; alpar@1: sql->mode = mode; alpar@1: sql->res = NULL; alpar@1: sql->query = NULL; alpar@1: sql->nf = mpl_tab_num_flds(dca); alpar@1: alpar@1: narg = mpl_tab_num_args(dca); alpar@1: if (narg < 3 ) alpar@1: xprintf("MySQL driver: string list too short \n"); alpar@1: alpar@1: /* get connection string*/ alpar@1: dsn = (char *) mpl_tab_get_arg(dca, 2); alpar@1: /* copy connection string*/ alpar@1: i = strlen(dsn); alpar@1: i++; alpar@1: arg = xmalloc(i * sizeof(char)); alpar@1: strcpy(arg, dsn); alpar@1: /*tokenize connection string*/ alpar@1: for (i = 1, keyword = strtok (arg, "="); (keyword != NULL); alpar@1: keyword = strtok (NULL, "="), i++) alpar@1: { alpar@1: value = strtok (NULL, ";"); alpar@1: if (value==NULL) alpar@1: { alpar@1: xprintf("db_mysql_open: Missing value for keyword %s\n", alpar@1: keyword); alpar@1: xfree(arg); alpar@1: xfree(sql); alpar@1: return NULL; alpar@1: } alpar@1: if (0 == strcmp(keyword, "Server")) alpar@1: server = value; alpar@1: else if (0 == strcmp(keyword, "Database")) alpar@1: database = value; alpar@1: else if (0 == strcmp(keyword, "UID")) alpar@1: user = value; alpar@1: else if (0 == strcmp(keyword, "PWD")) alpar@1: password = value; alpar@1: else if (0 == strcmp(keyword, "Port")) alpar@1: port = (unsigned int) atol(value); alpar@1: } alpar@1: /* Connect to database */ alpar@1: sql->con = dl_mysql_init(NULL); alpar@1: if (!dl_mysql_real_connect(sql->con, server, user, password, database, alpar@1: port, NULL, 0)) alpar@1: { alpar@1: xprintf("db_mysql_open: Connect failed\n"); alpar@1: xprintf("%s\n", dl_mysql_error(sql->con)); alpar@1: xfree(arg); alpar@1: xfree(sql); alpar@1: return NULL; alpar@1: } alpar@1: xfree(arg); alpar@1: alpar@1: for(j = 0; sqllines[j+1] != NULL; j++) alpar@1: { query = (char *) sqllines[j]; alpar@1: xprintf("%s\n", query); alpar@1: if (dl_mysql_query(sql->con, query)) alpar@1: { alpar@1: xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query); alpar@1: xprintf("%s\n",dl_mysql_error(sql->con)); alpar@1: dl_mysql_close(sql->con); alpar@1: xfree(sql); alpar@1: return NULL; alpar@1: } alpar@1: } alpar@1: alpar@1: if ( sql->mode == 'R' ) alpar@1: { sql->nf = mpl_tab_num_flds(dca); alpar@1: for(j = 0; sqllines[j] != NULL; j++) alpar@1: arg = (char *) sqllines[j]; alpar@1: total = strlen(arg); alpar@1: if (total > 7 && 0 == strncmp(arg, "SELECT ", 7)) alpar@1: { alpar@1: total = strlen(arg); alpar@1: query = xmalloc( (total+1) * sizeof(char)); alpar@1: strcpy (query, arg); alpar@1: } alpar@1: else alpar@1: { alpar@1: query = db_generate_select_stmt(dca); alpar@1: } alpar@1: xprintf("%s\n", query); alpar@1: if (dl_mysql_query(sql->con, query)) alpar@1: { alpar@1: xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query); alpar@1: xprintf("%s\n",dl_mysql_error(sql->con)); alpar@1: dl_mysql_close(sql->con); alpar@1: xfree(query); alpar@1: xfree(sql); alpar@1: return NULL; alpar@1: } alpar@1: xfree(query); alpar@1: sql->res = dl_mysql_use_result(sql->con); alpar@1: if (sql->res) alpar@1: { alpar@1: /* create references between query results and table fields*/ alpar@1: total = dl_mysql_num_fields(sql->res); alpar@1: if (total > SQL_FIELD_MAX) alpar@1: { xprintf("db_mysql_open: Too many fields (> %d) in query.\n" alpar@1: "\"%s\"\n", SQL_FIELD_MAX, query); alpar@1: xprintf("%s\n",dl_mysql_error(sql->con)); alpar@1: dl_mysql_close(sql->con); alpar@1: xfree(query); alpar@1: xfree(sql); alpar@1: return NULL; alpar@1: } alpar@1: fields = dl_mysql_fetch_fields(sql->res); alpar@1: for (i = 1; i <= total; i++) alpar@1: { alpar@1: for (j = sql->nf; j >= 1; j--) alpar@1: { alpar@1: if (strcmp(mpl_tab_get_name(dca, j), fields[i-1].name) alpar@1: == 0) alpar@1: break; alpar@1: } alpar@1: sql->ref[i] = j; alpar@1: } alpar@1: } alpar@1: else alpar@1: { alpar@1: if(dl_mysql_field_count(sql->con) == 0) alpar@1: { alpar@1: xprintf("db_mysql_open: Query was not a SELECT\n\"%s\"\n", alpar@1: query); alpar@1: xprintf("%s\n",dl_mysql_error(sql->con)); alpar@1: xfree(query); alpar@1: xfree(sql); alpar@1: return NULL; alpar@1: } alpar@1: else alpar@1: { alpar@1: xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query); alpar@1: xprintf("%s\n",dl_mysql_error(sql->con)); alpar@1: xfree(query); alpar@1: xfree(sql); alpar@1: return NULL; alpar@1: } alpar@1: } alpar@1: } alpar@1: else if ( sql->mode == 'W' ) alpar@1: { for(j = 0; sqllines[j] != NULL; j++) alpar@1: arg = (char *) sqllines[j]; alpar@1: if ( NULL != strchr(arg, '?') ) alpar@1: { alpar@1: total = strlen(arg); alpar@1: query = xmalloc( (total+1) * sizeof(char)); alpar@1: strcpy (query, arg); alpar@1: } alpar@1: else alpar@1: query = db_generate_insert_stmt(dca); alpar@1: sql->query = query; alpar@1: xprintf("%s\n", query); alpar@1: } alpar@1: return sql; alpar@1: } alpar@1: alpar@1: int db_mysql_read(TABDCA *dca, void *link) alpar@1: { struct db_mysql *sql; alpar@1: char buf[255+1]; alpar@1: char **row; alpar@1: unsigned long *lengths; alpar@1: MYSQL_FIELD *fields; alpar@1: double num; alpar@1: int len; alpar@1: unsigned long num_fields; alpar@1: int i; alpar@1: alpar@1: sql = (struct db_mysql *) link; alpar@1: alpar@1: xassert(sql != NULL); alpar@1: xassert(sql->mode == 'R'); alpar@1: if (NULL == sql->res) alpar@1: { alpar@1: xprintf("db_mysql_read: no result set available"); alpar@1: return 1; alpar@1: } alpar@1: if (NULL==(row = (char **)dl_mysql_fetch_row(sql->res))) { alpar@1: return -1; /*EOF*/ alpar@1: } alpar@1: lengths = dl_mysql_fetch_lengths(sql->res); alpar@1: fields = dl_mysql_fetch_fields(sql->res); alpar@1: num_fields = dl_mysql_num_fields(sql->res); alpar@1: for (i=1; i <= num_fields; i++) alpar@1: { alpar@1: if (row[i-1] != NULL) alpar@1: { len = (size_t) lengths[i-1]; alpar@1: if (len > 255) alpar@1: len = 255; alpar@1: strncpy(buf, (const char *) row[i-1], len); alpar@1: buf[len] = 0x00; alpar@1: if (0 != (fields[i-1].flags & NUM_FLAG)) alpar@1: { strspx(buf); /* remove spaces*/ alpar@1: if (str2num(buf, &num) != 0) alpar@1: { xprintf("'%s' cannot be converted to a number.\n", buf); alpar@1: return 1; alpar@1: } alpar@1: if (sql->ref[i] > 0) alpar@1: mpl_tab_set_num(dca, sql->ref[i], num); alpar@1: } alpar@1: else alpar@1: { if (sql->ref[i] > 0) alpar@1: mpl_tab_set_str(dca, sql->ref[i], strtrim(buf)); alpar@1: } alpar@1: } alpar@1: } alpar@1: return 0; alpar@1: } alpar@1: alpar@1: int db_mysql_write(TABDCA *dca, void *link) alpar@1: { alpar@1: struct db_mysql *sql; alpar@1: char *part; alpar@1: char *query; alpar@1: char *template; alpar@1: char num[50]; alpar@1: int k; alpar@1: int len; alpar@1: int nf; alpar@1: alpar@1: sql = (struct db_mysql *) link; alpar@1: xassert(sql != NULL); alpar@1: xassert(sql->mode == 'W'); alpar@1: alpar@1: len = strlen(sql->query); alpar@1: template = (char *) xmalloc( (len + 1) * sizeof(char) ); alpar@1: strcpy(template, sql->query); alpar@1: alpar@1: nf = mpl_tab_num_flds(dca); alpar@1: for (k = 1; k <= nf; k++) alpar@1: { switch (mpl_tab_get_type(dca, k)) alpar@1: { case 'N': alpar@1: len += 20; alpar@1: break; alpar@1: case 'S': alpar@1: len += db_escaped_string_length(mpl_tab_get_str(dca, k)); alpar@1: len += 2; alpar@1: break; alpar@1: default: alpar@1: xassert(dca != dca); alpar@1: } alpar@1: } alpar@1: query = xmalloc( (len + 1 ) * sizeof(char) ); alpar@1: query[0] = 0x00; alpar@1: for (k = 1, part = strtok (template, "?"); (part != NULL); alpar@1: part = strtok (NULL, "?"), k++) alpar@1: { alpar@1: if (k > nf) break; alpar@1: strcat( query, part ); alpar@1: switch (mpl_tab_get_type(dca, k)) alpar@1: { case 'N': alpar@1: #if 0 /* 02/XI-2010 by xypron */ alpar@1: sprintf(num, "%-18g",mpl_tab_get_num(dca, k)); alpar@1: #else alpar@1: sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k)); alpar@1: #endif alpar@1: strcat( query, num ); alpar@1: break; alpar@1: case 'S': alpar@1: strcat( query, "'"); alpar@1: db_escape_string( query + strlen(query), alpar@1: mpl_tab_get_str(dca, k) ); alpar@1: strcat( query, "'"); alpar@1: break; alpar@1: default: alpar@1: xassert(dca != dca); alpar@1: } alpar@1: } alpar@1: if (part != NULL) alpar@1: strcat(query, part); alpar@1: if (dl_mysql_query(sql->con, query)) alpar@1: { alpar@1: xprintf("db_mysql_write: Query\n\"%s\"\nfailed.\n", query); alpar@1: xprintf("%s\n",dl_mysql_error(sql->con)); alpar@1: xfree(query); alpar@1: xfree(template); alpar@1: return 1; alpar@1: } alpar@1: alpar@1: xfree(query); alpar@1: xfree(template); alpar@1: return 0; alpar@1: } alpar@1: alpar@1: int db_mysql_close(TABDCA *dca, void *link) alpar@1: { alpar@1: struct db_mysql *sql; alpar@1: alpar@1: sql = (struct db_mysql *) link; alpar@1: xassert(sql != NULL); alpar@1: dl_mysql_close(sql->con); alpar@1: if ( sql->mode == 'W' ) alpar@1: xfree(sql->query); alpar@1: xfree(sql); alpar@1: dca->link = NULL; alpar@1: return 0; alpar@1: } alpar@1: alpar@1: #endif alpar@1: alpar@1: /* eof */