mirror of
https://github.com/mdbtools/mdbtools.git
synced 2025-04-05 20:31:00 +08:00
2355 lines
64 KiB
C
2355 lines
64 KiB
C
/* MDB Tools - A library for reading MS Access database file
|
|
* Copyright (C) 2000 Brian Bruns
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#ifdef ENABLE_ODBC_W
|
|
#define SQL_NOUNICODEMAP
|
|
#define UNICODE
|
|
#endif //ENABLE_ODBC_W
|
|
|
|
#include <sql.h>
|
|
#include <sqlext.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <limits.h>
|
|
#include "mdbodbc.h"
|
|
|
|
//#define TRACE(x) fprintf(stderr,"Function %s\n", x);
|
|
#define TRACE(x)
|
|
|
|
#ifdef ENABLE_ODBC_W
|
|
static iconv_t iconv_in,iconv_out;
|
|
#endif //ENABLE_ODBC_W
|
|
|
|
static SQLSMALLINT _odbc_get_client_type(MdbColumn *col);
|
|
static const char * _odbc_get_client_type_name(MdbColumn *col);
|
|
static int _odbc_fix_literals(struct _hstmt *stmt);
|
|
//static int _odbc_get_server_type(int clt_type);
|
|
static int _odbc_get_string_size(int size, SQLCHAR *str);
|
|
|
|
static void bind_columns (struct _hstmt*);
|
|
static void unbind_columns (struct _hstmt*);
|
|
|
|
#define FILL_FIELD(f,v,s) mdb_fill_temp_field(f,v,s,0,0,0,0)
|
|
|
|
#ifndef MIN
|
|
#define MIN(a,b) (a>b ? b : a)
|
|
#endif
|
|
#define _MAX_ERROR_LEN 255
|
|
static char lastError[_MAX_ERROR_LEN+1];
|
|
static char sqlState[6];
|
|
|
|
typedef struct {
|
|
SQLCHAR *type_name;
|
|
SQLSMALLINT data_type;
|
|
SQLINTEGER column_size;
|
|
SQLCHAR *literal_prefix;
|
|
SQLCHAR *literal_suffix;
|
|
SQLCHAR *create_params;
|
|
SQLSMALLINT nullable;
|
|
SQLSMALLINT case_sensitive;
|
|
SQLSMALLINT searchable;
|
|
SQLSMALLINT *unsigned_attribute;
|
|
SQLSMALLINT fixed_prec_scale;
|
|
SQLSMALLINT auto_unique_value;
|
|
SQLCHAR *local_type_name;
|
|
SQLSMALLINT minimum_scale;
|
|
SQLSMALLINT maximum_scale;
|
|
SQLSMALLINT sql_data_type;
|
|
SQLSMALLINT *sql_datetime_sub;
|
|
SQLSMALLINT *num_prec_radix;
|
|
SQLSMALLINT *interval_precision;
|
|
} TypeInfo;
|
|
|
|
TypeInfo type_info[] = {
|
|
{(SQLCHAR*)"text", SQL_VARCHAR, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_VARCHAR, NULL, NULL, NULL},
|
|
{(SQLCHAR*)"memo", SQL_VARCHAR, 4096, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 4096, SQL_VARCHAR, NULL, NULL, NULL},
|
|
{(SQLCHAR*)"ole", SQL_VARCHAR, MDB_BIND_SIZE, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, MDB_BIND_SIZE, SQL_VARCHAR, NULL, NULL, NULL},
|
|
{(SQLCHAR*)"text", SQL_CHAR, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_CHAR, NULL, NULL, NULL},
|
|
{(SQLCHAR*)"numeric", SQL_NUMERIC, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_NUMERIC, NULL, NULL, NULL},
|
|
{(SQLCHAR*)"numeric", SQL_DECIMAL, 255, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_FALSE, NULL, 0, 255, SQL_DECIMAL, NULL, NULL, NULL},
|
|
{(SQLCHAR*)"long integer", SQL_INTEGER, 4, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_TRUE, NULL, 0, 4, SQL_INTEGER, NULL, NULL, NULL},
|
|
{(SQLCHAR*)"integer", SQL_SMALLINT, 4, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_TRUE, NULL, 0, 4, SQL_SMALLINT, NULL, NULL, NULL},
|
|
{(SQLCHAR*)"integer", SQL_SMALLINT, 4, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_TRUE, NULL, 0, 4, SQL_SMALLINT, NULL, NULL, NULL},
|
|
{(SQLCHAR*)"single", SQL_REAL, 4, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_TRUE, NULL, 0, 4, SQL_REAL, NULL, NULL, NULL},
|
|
{(SQLCHAR*)"double", SQL_DOUBLE, 8, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_TRUE, NULL, 0, 8, SQL_FLOAT, NULL, NULL, NULL},
|
|
{(SQLCHAR*)"datetime", SQL_DATETIME, 8, NULL, NULL, NULL, SQL_TRUE, SQL_TRUE, SQL_TRUE, NULL, SQL_FALSE, SQL_TRUE, NULL, 0, 8, SQL_DATETIME, NULL, NULL, NULL}
|
|
};
|
|
|
|
#define NUM_TYPE_INFO_COLS 19
|
|
#define MAX_TYPE_INFO 11
|
|
|
|
#ifdef ENABLE_ODBC_W
|
|
void my_fini(void);
|
|
|
|
MDB_CONSTRUCTOR(my_init)
|
|
{
|
|
TRACE("my_init");
|
|
int endian = 1;
|
|
const char* wcharset;
|
|
if (sizeof(SQLWCHAR) == 2)
|
|
if (*(char*)&endian == 1)
|
|
wcharset = "UCS-2LE";
|
|
else
|
|
wcharset = "UCS-2BE";
|
|
else if (sizeof(SQLWCHAR) == 4)
|
|
if (*(char*)&endian == 1)
|
|
wcharset = "UCS-4LE";
|
|
else
|
|
wcharset = "UCS-4BE";
|
|
else
|
|
fprintf(stderr, "Unsupported SQLWCHAR width %zd\n", sizeof(SQLWCHAR));
|
|
//fprintf(stderr,"charset %s\n", wcharset);
|
|
//fprintf(stderr, "SQLWCHAR width %d\n", sizeof(SQLWCHAR));
|
|
/*
|
|
#if __SIZEOF_WCHAR_T__ == 4 || __WCHAR_MAX__ > 0x10000
|
|
#define WCHAR_CHARSET "UCS-4LE"
|
|
#else
|
|
#define WCHAR_CHARSET "UCS-2LE"
|
|
#endif
|
|
*/
|
|
iconv_out = iconv_open(wcharset, "UTF-8");
|
|
iconv_in = iconv_open("UTF-8", wcharset);
|
|
|
|
atexit(my_fini);
|
|
}
|
|
|
|
void my_fini()
|
|
{
|
|
TRACE("my_fini");
|
|
if(iconv_out != (iconv_t)-1)iconv_close(iconv_out);
|
|
if(iconv_in != (iconv_t)-1)iconv_close(iconv_in);
|
|
}
|
|
|
|
static int unicode2ascii(char *_in, size_t *_lin, char *_out, size_t *_lout){
|
|
char *in=_in, *out=_out;
|
|
size_t lin=*_lin, lout=*_lout;
|
|
int ret = iconv(iconv_in, &in, &lin, &out, &lout);
|
|
*_lin -= lin;
|
|
*_lout -= lout;
|
|
return ret;
|
|
}
|
|
|
|
static int ascii2unicode(char *_in, size_t *_lin, char *_out, size_t *_lout){
|
|
//fprintf(stderr,"ascii2unicode %08x %08x %08x %08x\n",_in,_lin,_out,_lout);
|
|
char *in=_in, *out=_out;
|
|
size_t lin=*_lin, lout=*_lout;
|
|
//fprintf(stderr,"ascii2unicode %zd %zd\n",lin,lout);
|
|
int ret = iconv(iconv_out, &in, &lin, &out, &lout);
|
|
*_lin -= lin;
|
|
*_lout -= lout;
|
|
return ret;
|
|
}
|
|
|
|
static int sqlwlen(SQLWCHAR *p){
|
|
int r=0;
|
|
for(;*p;r++)
|
|
p++;
|
|
return r;
|
|
}
|
|
#endif // ENABLE_ODBC_W
|
|
|
|
/* The SQL engine is presently non-reenterrant and non-thread safe.
|
|
See SQLExecute for details.
|
|
*/
|
|
|
|
static void LogError (const char* format, ...)
|
|
{
|
|
/*
|
|
* Someday, I might make this store more than one error.
|
|
*/
|
|
va_list argp;
|
|
va_start(argp, format);
|
|
vsnprintf(lastError, _MAX_ERROR_LEN, format, argp);
|
|
va_end(argp);
|
|
}
|
|
|
|
static SQLRETURN do_connect (
|
|
SQLHDBC hdbc,
|
|
char *database)
|
|
{
|
|
struct _hdbc *dbc = (struct _hdbc *) hdbc;
|
|
|
|
if (mdb_sql_open(dbc->sqlconn, database))
|
|
return SQL_SUCCESS;
|
|
else
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLDriverConnect(
|
|
SQLHDBC hdbc,
|
|
SQLHWND hwnd,
|
|
SQLCHAR *szConnStrIn,
|
|
SQLSMALLINT cbConnStrIn,
|
|
SQLCHAR *szConnStrOut,
|
|
SQLSMALLINT cbConnStrOutMax,
|
|
SQLSMALLINT *pcbConnStrOut,
|
|
SQLUSMALLINT fDriverCompletion)
|
|
{
|
|
char* database = NULL;
|
|
ConnectParams* params;
|
|
SQLRETURN ret;
|
|
|
|
TRACE("SQLDriverConnect");
|
|
strcpy (lastError, "");
|
|
|
|
params = ((struct _hdbc*) hdbc)->params;
|
|
|
|
if (ExtractDSN(params, (gchar*)szConnStrIn)) {
|
|
SetConnectString (params, (gchar*)szConnStrIn);
|
|
if (!(database = GetConnectParam (params, "Database"))){
|
|
LogError ("Could not find Database parameter in '%s'", szConnStrIn);
|
|
return SQL_ERROR;
|
|
}
|
|
ret = do_connect (hdbc, database);
|
|
return ret;
|
|
}
|
|
if ((database = ExtractDBQ (params, (gchar*)szConnStrIn))) {
|
|
ret = do_connect (hdbc, database);
|
|
return ret;
|
|
}
|
|
LogError ("Could not find DSN nor DBQ in connect string '%s'", szConnStrIn);
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
#ifdef ENABLE_ODBC_W
|
|
SQLRETURN SQL_API SQLDriverConnectW(
|
|
SQLHDBC hdbc,
|
|
SQLHWND hwnd,
|
|
SQLWCHAR *szConnStrIn,
|
|
SQLSMALLINT cbConnStrIn,
|
|
SQLWCHAR *szConnStrOut,
|
|
SQLSMALLINT cbConnStrOutMax,
|
|
SQLSMALLINT *pcbConnStrOut,
|
|
SQLUSMALLINT fDriverCompletion)
|
|
{
|
|
TRACE("SQLDriverConnectW");
|
|
if(cbConnStrIn==SQL_NTS)cbConnStrIn=sqlwlen(szConnStrIn);
|
|
{
|
|
size_t l = cbConnStrIn*sizeof(SQLWCHAR), z = (cbConnStrIn+1)*3;
|
|
SQLCHAR *tmp = malloc(z);
|
|
SQLRETURN ret;
|
|
unicode2ascii((char*)szConnStrIn, &l, (char*)tmp, &z);
|
|
tmp[z] = 0;
|
|
ret = SQLDriverConnect(hdbc,hwnd,tmp,SQL_NTS,NULL,0,pcbConnStrOut,fDriverCompletion);
|
|
free(tmp);
|
|
if (szConnStrOut && cbConnStrOutMax>0)
|
|
szConnStrOut[0] = 0;
|
|
if (pcbConnStrOut)
|
|
*pcbConnStrOut = 0;
|
|
return ret;
|
|
}
|
|
}
|
|
#endif // ENABLE_ODBC_W
|
|
|
|
SQLRETURN SQL_API SQLBrowseConnect(
|
|
SQLHDBC hdbc,
|
|
SQLCHAR *szConnStrIn,
|
|
SQLSMALLINT cbConnStrIn,
|
|
SQLCHAR *szConnStrOut,
|
|
SQLSMALLINT cbConnStrOutMax,
|
|
SQLSMALLINT *pcbConnStrOut)
|
|
{
|
|
TRACE("SQLBrowseConnect");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLColumnPrivileges(
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szCatalogName,
|
|
SQLSMALLINT cbCatalogName,
|
|
SQLCHAR *szSchemaName,
|
|
SQLSMALLINT cbSchemaName,
|
|
SQLCHAR *szTableName,
|
|
SQLSMALLINT cbTableName,
|
|
SQLCHAR *szColumnName,
|
|
SQLSMALLINT cbColumnName)
|
|
{
|
|
TRACE("SQLColumnPrivileges");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLDescribeParam(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT ipar,
|
|
SQLSMALLINT *pfSqlType,
|
|
SQLULEN *pcbParamDef,
|
|
SQLSMALLINT *pibScale,
|
|
SQLSMALLINT *pfNullable)
|
|
{
|
|
TRACE("SQLDescribeParam");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLExtendedFetch(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT fFetchType,
|
|
SQLLEN irow,
|
|
SQLULEN *pcrow,
|
|
SQLUSMALLINT *rgfRowStatus)
|
|
{
|
|
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
|
|
|
TRACE("SQLExtendedFetch");
|
|
if (fFetchType!=SQL_FETCH_NEXT) {
|
|
LogError("Fetch type not supported in SQLExtendedFetch");
|
|
return SQL_ERROR;
|
|
}
|
|
if (pcrow)
|
|
*pcrow=1;
|
|
if (rgfRowStatus)
|
|
*rgfRowStatus = SQL_SUCCESS; /* what is the row status value? */
|
|
|
|
bind_columns(stmt);
|
|
|
|
if (mdb_fetch_row(stmt->sql->cur_table)) {
|
|
stmt->rows_affected++;
|
|
return SQL_SUCCESS;
|
|
} else {
|
|
return SQL_NO_DATA_FOUND;
|
|
}
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLForeignKeys(
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szPkCatalogName,
|
|
SQLSMALLINT cbPkCatalogName,
|
|
SQLCHAR *szPkSchemaName,
|
|
SQLSMALLINT cbPkSchemaName,
|
|
SQLCHAR *szPkTableName,
|
|
SQLSMALLINT cbPkTableName,
|
|
SQLCHAR *szFkCatalogName,
|
|
SQLSMALLINT cbFkCatalogName,
|
|
SQLCHAR *szFkSchemaName,
|
|
SQLSMALLINT cbFkSchemaName,
|
|
SQLCHAR *szFkTableName,
|
|
SQLSMALLINT cbFkTableName)
|
|
{
|
|
TRACE("SQLForeignKeys");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLMoreResults(
|
|
SQLHSTMT hstmt)
|
|
{
|
|
TRACE("SQLMoreResults");
|
|
return SQL_NO_DATA;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLNativeSql(
|
|
SQLHDBC hdbc,
|
|
SQLCHAR *szSqlStrIn,
|
|
SQLINTEGER cbSqlStrIn,
|
|
SQLCHAR *szSqlStr,
|
|
SQLINTEGER cbSqlStrMax,
|
|
SQLINTEGER *pcbSqlStr)
|
|
{
|
|
TRACE("SQLNativeSql");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLNumParams(
|
|
SQLHSTMT hstmt,
|
|
SQLSMALLINT *pcpar)
|
|
{
|
|
TRACE("SQLNumParams");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLParamOptions(
|
|
SQLHSTMT hstmt,
|
|
SQLULEN crow,
|
|
SQLULEN *pirow)
|
|
{
|
|
TRACE("SQLParamOptions");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLPrimaryKeys(
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szCatalogName,
|
|
SQLSMALLINT cbCatalogName,
|
|
SQLCHAR *szSchemaName,
|
|
SQLSMALLINT cbSchemaName,
|
|
SQLCHAR *szTableName,
|
|
SQLSMALLINT cbTableName)
|
|
{
|
|
TRACE("SQLPrimaryKeys");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLProcedureColumns(
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szCatalogName,
|
|
SQLSMALLINT cbCatalogName,
|
|
SQLCHAR *szSchemaName,
|
|
SQLSMALLINT cbSchemaName,
|
|
SQLCHAR *szProcName,
|
|
SQLSMALLINT cbProcName,
|
|
SQLCHAR *szColumnName,
|
|
SQLSMALLINT cbColumnName)
|
|
{
|
|
TRACE("SQLProcedureColumns");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLProcedures(
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szCatalogName,
|
|
SQLSMALLINT cbCatalogName,
|
|
SQLCHAR *szSchemaName,
|
|
SQLSMALLINT cbSchemaName,
|
|
SQLCHAR *szProcName,
|
|
SQLSMALLINT cbProcName)
|
|
{
|
|
TRACE("SQLProcedures");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLSetPos(
|
|
SQLHSTMT hstmt,
|
|
SQLSETPOSIROW irow,
|
|
SQLUSMALLINT fOption,
|
|
SQLUSMALLINT fLock)
|
|
{
|
|
TRACE("SQLSetPos");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLTablePrivileges(
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szCatalogName,
|
|
SQLSMALLINT cbCatalogName,
|
|
SQLCHAR *szSchemaName,
|
|
SQLSMALLINT cbSchemaName,
|
|
SQLCHAR *szTableName,
|
|
SQLSMALLINT cbTableName)
|
|
{
|
|
TRACE("SQLTablePrivileges");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLDrivers(
|
|
SQLHENV henv,
|
|
SQLUSMALLINT fDirection,
|
|
SQLCHAR *szDriverDesc,
|
|
SQLSMALLINT cbDriverDescMax,
|
|
SQLSMALLINT *pcbDriverDesc,
|
|
SQLCHAR *szDriverAttributes,
|
|
SQLSMALLINT cbDrvrAttrMax,
|
|
SQLSMALLINT *pcbDrvrAttr)
|
|
{
|
|
TRACE("SQLDrivers");
|
|
return SQL_SUCCESS;
|
|
}
|
|
SQLRETURN SQL_API SQLSetEnvAttr (
|
|
SQLHENV EnvironmentHandle,
|
|
SQLINTEGER Attribute,
|
|
SQLPOINTER Value,
|
|
SQLINTEGER StringLength)
|
|
{
|
|
TRACE("SQLSetEnvAttr");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLBindParameter(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT ipar,
|
|
SQLSMALLINT fParamType,
|
|
SQLSMALLINT fCType,
|
|
SQLSMALLINT fSqlType,
|
|
SQLULEN cbColDef,
|
|
SQLSMALLINT ibScale,
|
|
SQLPOINTER rgbValue,
|
|
SQLLEN cbValueMax,
|
|
SQLLEN *pcbValue)
|
|
{
|
|
/*struct _hstmt *stmt;*/
|
|
|
|
TRACE("SQLBindParameter");
|
|
/*stmt = (struct _hstmt *) hstmt;*/
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLAllocConnect(
|
|
SQLHENV henv,
|
|
SQLHDBC *phdbc)
|
|
{
|
|
struct _henv *env;
|
|
struct _hdbc* dbc;
|
|
|
|
TRACE("SQLAllocConnect");
|
|
env = (struct _henv *) henv;
|
|
dbc = (SQLHDBC) g_malloc0(sizeof(struct _hdbc));
|
|
dbc->henv=env;
|
|
g_ptr_array_add(env->connections, dbc);
|
|
dbc->params = NewConnectParams ();
|
|
dbc->statements = g_ptr_array_new();
|
|
dbc->sqlconn = mdb_sql_init();
|
|
*phdbc=dbc;
|
|
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLAllocEnv(
|
|
SQLHENV *phenv)
|
|
{
|
|
struct _henv *env;
|
|
|
|
TRACE("SQLAllocEnv");
|
|
env = (SQLHENV) g_malloc0(sizeof(struct _henv));
|
|
env->connections = g_ptr_array_new();
|
|
*phenv=env;
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLAllocStmt(
|
|
SQLHDBC hdbc,
|
|
SQLHSTMT *phstmt)
|
|
{
|
|
struct _hdbc *dbc;
|
|
struct _hstmt *stmt;
|
|
|
|
TRACE("SQLAllocStmt");
|
|
dbc = (struct _hdbc *) hdbc;
|
|
|
|
stmt = (SQLHSTMT) g_malloc0(sizeof(struct _hstmt));
|
|
stmt->hdbc=dbc;
|
|
g_ptr_array_add(dbc->statements, stmt);
|
|
stmt->sql = mdb_sql_init();
|
|
stmt->sql->mdb = mdb_clone_handle(dbc->sqlconn->mdb);
|
|
|
|
*phstmt = stmt;
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLAllocHandle(
|
|
SQLSMALLINT HandleType,
|
|
SQLHANDLE InputHandle,
|
|
SQLHANDLE * OutputHandle)
|
|
{
|
|
SQLRETURN retval = SQL_ERROR;
|
|
TRACE("SQLAllocHandle");
|
|
switch(HandleType) {
|
|
case SQL_HANDLE_STMT:
|
|
retval = SQLAllocStmt(InputHandle,OutputHandle);
|
|
break;
|
|
case SQL_HANDLE_DBC:
|
|
retval = SQLAllocConnect(InputHandle,OutputHandle);
|
|
break;
|
|
case SQL_HANDLE_ENV:
|
|
retval = SQLAllocEnv(OutputHandle);
|
|
break;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLBindCol(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT icol,
|
|
SQLSMALLINT fCType,
|
|
SQLPOINTER rgbValue,
|
|
SQLLEN cbValueMax,
|
|
SQLLEN *pcbValue)
|
|
{
|
|
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
|
struct _sql_bind_info *cur, *newitem;
|
|
|
|
TRACE("SQLBindCol");
|
|
/* find available item in list */
|
|
cur = stmt->bind_head;
|
|
while (cur) {
|
|
if (cur->column_number==icol)
|
|
break;
|
|
cur = cur->next;
|
|
}
|
|
/* if this is a repeat */
|
|
if (cur) {
|
|
cur->column_bindtype = fCType;
|
|
cur->column_lenbind = (int *)pcbValue;
|
|
cur->column_bindlen = cbValueMax;
|
|
cur->varaddr = (char *) rgbValue;
|
|
} else {
|
|
/* didn't find it create a new one */
|
|
newitem = (struct _sql_bind_info *) g_malloc0(sizeof(struct _sql_bind_info));
|
|
newitem->column_number = icol;
|
|
newitem->column_bindtype = fCType;
|
|
newitem->column_bindlen = cbValueMax;
|
|
newitem->column_lenbind = (int *)pcbValue;
|
|
newitem->varaddr = (char *) rgbValue;
|
|
/* if there's no head yet */
|
|
if (! stmt->bind_head) {
|
|
stmt->bind_head = newitem;
|
|
} else {
|
|
/* find the tail of the list */
|
|
cur = stmt->bind_head;
|
|
while (cur->next) {
|
|
cur = cur->next;
|
|
}
|
|
cur->next = newitem;
|
|
}
|
|
}
|
|
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLCancel(
|
|
SQLHSTMT hstmt)
|
|
{
|
|
TRACE("SQLCancel");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLConnect(
|
|
SQLHDBC hdbc,
|
|
SQLCHAR *szDSN,
|
|
SQLSMALLINT cbDSN,
|
|
SQLCHAR *szUID,
|
|
SQLSMALLINT cbUID,
|
|
SQLCHAR *szAuthStr,
|
|
SQLSMALLINT cbAuthStr)
|
|
{
|
|
char* database = NULL;
|
|
ConnectParams* params;
|
|
SQLRETURN ret;
|
|
|
|
TRACE("SQLConnect");
|
|
strcpy (lastError, "");
|
|
|
|
params = ((struct _hdbc*) hdbc)->params;
|
|
|
|
params->dsnName = g_string_assign (params->dsnName, (gchar*)szDSN);
|
|
|
|
if (!(database = GetConnectParam (params, "Database")))
|
|
{
|
|
LogError ("Could not find Database parameter in '%s'", szDSN);
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
ret = do_connect (hdbc, database);
|
|
return ret;
|
|
}
|
|
|
|
#ifdef ENABLE_ODBC_W
|
|
SQLRETURN SQL_API SQLConnectW(
|
|
SQLHDBC hdbc,
|
|
SQLWCHAR *szDSN,
|
|
SQLSMALLINT cbDSN,
|
|
SQLWCHAR *szUID,
|
|
SQLSMALLINT cbUID,
|
|
SQLWCHAR *szAuthStr,
|
|
SQLSMALLINT cbAuthStr)
|
|
{
|
|
TRACE("SQLConnectW");
|
|
if(cbDSN==SQL_NTS)cbDSN=sqlwlen(szDSN);
|
|
if(cbUID==SQL_NTS)cbUID=sqlwlen(szUID);
|
|
if(cbAuthStr==SQL_NTS)cbAuthStr=sqlwlen(szAuthStr);
|
|
{
|
|
SQLCHAR *tmp1=calloc(cbDSN*4,1),*tmp2=calloc(cbUID*4,1),*tmp3=calloc(cbAuthStr*4,1);
|
|
size_t l1=cbDSN*4,z1=cbDSN*2;
|
|
size_t l2=cbUID*4,z2=cbUID*2;
|
|
size_t l3=cbAuthStr*4,z3=cbAuthStr*2;
|
|
SQLRETURN ret;
|
|
unicode2ascii((char*)szDSN, &z1, (char*)tmp1, &l1);
|
|
unicode2ascii((char*)szUID, &z2, (char*)tmp2, &l2);
|
|
unicode2ascii((char*)szAuthStr, &z3, (char*)tmp3, &l3);
|
|
ret = SQLConnect(hdbc, tmp1, l1, tmp2, l2, tmp3, l3);
|
|
free(tmp1),free(tmp2),free(tmp3);
|
|
return ret;
|
|
}
|
|
}
|
|
#endif //ENABLE_ODBC_W
|
|
|
|
SQLRETURN SQL_API SQLDescribeCol(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT icol,
|
|
SQLCHAR *szColName,
|
|
SQLSMALLINT cbColNameMax,
|
|
SQLSMALLINT *pcbColName,
|
|
SQLSMALLINT *pfSqlType,
|
|
SQLULEN *pcbColDef, /* precision */
|
|
SQLSMALLINT *pibScale,
|
|
SQLSMALLINT *pfNullable)
|
|
{
|
|
int i;
|
|
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
|
MdbSQL *sql = stmt->sql;
|
|
MdbSQLColumn *sqlcol;
|
|
MdbColumn *col;
|
|
MdbTableDef *table;
|
|
SQLRETURN ret;
|
|
|
|
TRACE("SQLDescribeCol");
|
|
if (icol<1 || icol>sql->num_columns) {
|
|
strcpy(sqlState, "07009"); // Invalid descriptor index
|
|
return SQL_ERROR;
|
|
}
|
|
sqlcol = g_ptr_array_index(sql->columns,icol - 1);
|
|
table = sql->cur_table;
|
|
for (i=0;i<table->num_cols;i++) {
|
|
col=g_ptr_array_index(table->columns,i);
|
|
if (!g_ascii_strcasecmp(sqlcol->name, col->name)) {
|
|
break;
|
|
}
|
|
}
|
|
if (i==table->num_cols) {
|
|
fprintf(stderr, "Column %s lost\n", (char*)sqlcol->name);
|
|
strcpy(sqlState, "07009"); // Invalid descriptor index
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
ret = SQL_SUCCESS;
|
|
if (pcbColName)
|
|
*pcbColName=strlen(sqlcol->name);
|
|
if (szColName) {
|
|
if (cbColNameMax < 0) {
|
|
strcpy(sqlState, "HY090"); // Invalid string or buffer length
|
|
return SQL_ERROR;
|
|
}
|
|
if (snprintf((char *)szColName, cbColNameMax, "%s", sqlcol->name) + 1 > cbColNameMax) {
|
|
strcpy(sqlState, "01004"); // String data, right truncated
|
|
ret = SQL_SUCCESS_WITH_INFO;
|
|
}
|
|
}
|
|
if (pfSqlType) {
|
|
*pfSqlType = _odbc_get_client_type(col);
|
|
}
|
|
if (pcbColDef) {
|
|
*pcbColDef = col->col_size;
|
|
}
|
|
if (pibScale) {
|
|
/* FIX ME */
|
|
*pibScale = 0;
|
|
}
|
|
if (pfNullable) {
|
|
*pfNullable = !col->is_fixed;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef ENABLE_ODBC_W
|
|
SQLRETURN SQL_API SQLDescribeColW(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT icol,
|
|
SQLWCHAR *szColName,
|
|
SQLSMALLINT cbColNameMax,
|
|
SQLSMALLINT *pcbColName,
|
|
SQLSMALLINT *pfSqlType,
|
|
SQLULEN *pcbColDef, /* precision */
|
|
SQLSMALLINT *pibScale,
|
|
SQLSMALLINT *pfNullable)
|
|
{
|
|
TRACE("SQLDescribeColW");
|
|
if(cbColNameMax==SQL_NTS)cbColNameMax=sqlwlen(szColName);
|
|
{
|
|
SQLCHAR *tmp=calloc(cbColNameMax*4,1);
|
|
size_t l=cbColNameMax*4;
|
|
SQLRETURN ret = SQLDescribeCol(hstmt, icol, tmp, cbColNameMax*4, (SQLSMALLINT*)&l, pfSqlType, pcbColDef, pibScale, pfNullable);
|
|
ascii2unicode((char*)tmp, &l, (char*)szColName, (size_t*)pcbColName);
|
|
*pcbColName/=sizeof(SQLWCHAR);
|
|
free(tmp);
|
|
return ret;
|
|
}
|
|
}
|
|
#endif //ENABLE_ODBC_W
|
|
|
|
SQLRETURN SQL_API SQLColAttributes(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT icol,
|
|
SQLUSMALLINT fDescType,
|
|
SQLPOINTER rgbDesc,
|
|
SQLSMALLINT cbDescMax,
|
|
SQLSMALLINT *pcbDesc,
|
|
SQLLEN *pfDesc)
|
|
{
|
|
int i;
|
|
struct _hstmt *stmt;
|
|
MdbSQL *sql;
|
|
MdbSQLColumn *sqlcol;
|
|
MdbColumn *col;
|
|
MdbTableDef *table;
|
|
SQLRETURN ret;
|
|
|
|
TRACE("SQLColAttributes");
|
|
stmt = (struct _hstmt *) hstmt;
|
|
sql = stmt->sql;
|
|
|
|
/* dont check column index for these */
|
|
switch(fDescType) {
|
|
case SQL_COLUMN_COUNT:
|
|
case SQL_DESC_COUNT:
|
|
*pfDesc = stmt->sql->num_columns;
|
|
return SQL_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
if (icol<1 || icol>sql->num_columns) {
|
|
strcpy(sqlState, "07009"); // Invalid descriptor index
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
/* find the column */
|
|
sqlcol = g_ptr_array_index(sql->columns,icol - 1);
|
|
table = sql->cur_table;
|
|
for (i=0;i<table->num_cols;i++) {
|
|
col=g_ptr_array_index(table->columns,i);
|
|
if (!g_ascii_strcasecmp(sqlcol->name, col->name)) {
|
|
break;
|
|
}
|
|
}
|
|
if (i==table->num_cols) {
|
|
strcpy(sqlState, "07009"); // Invalid descriptor index
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
// fprintf(stderr,"fDescType = %d\n", fDescType);
|
|
ret = SQL_SUCCESS;
|
|
switch(fDescType) {
|
|
case SQL_COLUMN_NAME: case SQL_DESC_NAME:
|
|
case SQL_COLUMN_LABEL: /* = SQL_DESC_LABEL */
|
|
if (cbDescMax < 0) {
|
|
strcpy(sqlState, "HY090"); // Invalid string or buffer length
|
|
return SQL_ERROR;
|
|
}
|
|
if (snprintf(rgbDesc, cbDescMax, "%s", sqlcol->name) + 1 > cbDescMax) {
|
|
strcpy(sqlState, "01004"); // String data, right truncated
|
|
ret = SQL_SUCCESS_WITH_INFO;
|
|
}
|
|
break;
|
|
case SQL_COLUMN_TYPE: /* =SQL_DESC_CONCISE_TYPE */
|
|
//*pfDesc = SQL_CHAR;
|
|
*pfDesc = _odbc_get_client_type(col);
|
|
break;
|
|
case SQL_COLUMN_TYPE_NAME:
|
|
{
|
|
const char *type_name = _odbc_get_client_type_name(col);
|
|
if (type_name)
|
|
*pcbDesc = snprintf(rgbDesc, cbDescMax, "%s", type_name);
|
|
break;
|
|
}
|
|
case SQL_COLUMN_LENGTH:
|
|
break;
|
|
case SQL_COLUMN_DISPLAY_SIZE: /* =SQL_DESC_DISPLAY_SIZE */
|
|
*pfDesc = mdb_col_disp_size(col);
|
|
break;
|
|
case SQL_DESC_UNSIGNED:
|
|
switch(col->col_type) {
|
|
case MDB_INT:
|
|
case MDB_LONGINT:
|
|
case MDB_FLOAT:
|
|
case MDB_DOUBLE:
|
|
case MDB_NUMERIC:
|
|
*pfDesc = SQL_FALSE;
|
|
break;
|
|
case MDB_BYTE:
|
|
default: // Everything else returns true per MSDN
|
|
*pfDesc = SQL_TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
case SQL_DESC_UPDATABLE:
|
|
*pfDesc = SQL_ATTR_READONLY;
|
|
break;
|
|
default:
|
|
strcpy(sqlState, "HYC00"); // Driver not capable
|
|
ret = SQL_ERROR;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#ifdef ENABLE_ODBC_W
|
|
SQLRETURN SQL_API SQLColAttributesW(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT icol,
|
|
SQLUSMALLINT fDescType,
|
|
SQLPOINTER rgbDesc,
|
|
SQLSMALLINT cbDescMax,
|
|
SQLSMALLINT *pcbDesc,
|
|
SQLLEN *pfDesc)
|
|
{
|
|
TRACE("SQLColAttributesW");
|
|
if (fDescType!=SQL_COLUMN_NAME && fDescType!=SQL_COLUMN_LABEL)
|
|
return SQLColAttributes(hstmt,icol,fDescType,rgbDesc,cbDescMax,pcbDesc,pfDesc);
|
|
else{
|
|
SQLCHAR *tmp=calloc(cbDescMax*4,1);
|
|
size_t l=cbDescMax*4;
|
|
SQLRETURN ret=SQLColAttributes(hstmt,icol,fDescType,tmp,cbDescMax*4,(SQLSMALLINT*)&l,pfDesc);
|
|
ascii2unicode((char*)tmp, &l, (char*)rgbDesc, (size_t*)pcbDesc);
|
|
*pcbDesc/=sizeof(SQLWCHAR);
|
|
free(tmp);
|
|
return ret;
|
|
}
|
|
}
|
|
#endif //ENABLE_ODBC_W
|
|
|
|
SQLRETURN SQL_API SQLDisconnect(
|
|
SQLHDBC hdbc)
|
|
{
|
|
struct _hdbc *dbc;
|
|
|
|
TRACE("SQLDisconnect");
|
|
|
|
dbc = (struct _hdbc *) hdbc;
|
|
// Automatically close all statements:
|
|
while (dbc->statements->len)
|
|
SQLFreeStmt(g_ptr_array_index(dbc->statements, 0), SQL_DROP);
|
|
mdb_sql_close(dbc->sqlconn);
|
|
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLError(
|
|
SQLHENV henv,
|
|
SQLHDBC hdbc,
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szSqlState,
|
|
SQLINTEGER *pfNativeError,
|
|
SQLCHAR *szErrorMsg,
|
|
SQLSMALLINT cbErrorMsgMax,
|
|
SQLSMALLINT *pcbErrorMsg)
|
|
{
|
|
SQLRETURN result = SQL_NO_DATA_FOUND;
|
|
|
|
TRACE("SQLError");
|
|
//if(pfNativeError)fprintf(stderr,"NativeError %05d\n", *pfNativeError);
|
|
if (strlen (lastError) > 0)
|
|
{
|
|
strcpy ((char*)szSqlState, "08001");
|
|
strcpy ((char*)szErrorMsg, lastError);
|
|
if (pcbErrorMsg)
|
|
*pcbErrorMsg = strlen (lastError);
|
|
if (pfNativeError)
|
|
*pfNativeError = 1;
|
|
|
|
result = SQL_SUCCESS;
|
|
strcpy (lastError, "");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#ifdef ENABLE_ODBC_W
|
|
SQLRETURN SQL_API SQLErrorW(
|
|
SQLHENV henv,
|
|
SQLHDBC hdbc,
|
|
SQLHSTMT hstmt,
|
|
SQLWCHAR *szSqlState,
|
|
SQLINTEGER *pfNativeError,
|
|
SQLWCHAR *szErrorMsg,
|
|
SQLSMALLINT cbErrorMsgMax,
|
|
SQLSMALLINT *pcbErrorMsg)
|
|
{
|
|
SQLCHAR szSqlState8[6];
|
|
SQLCHAR szErrorMsg8[3*cbErrorMsgMax+1];
|
|
SQLSMALLINT pcbErrorMsg8;
|
|
SQLRETURN result;
|
|
|
|
TRACE("SQLErrorW");
|
|
|
|
result = SQLError(henv, hdbc, hstmt, szSqlState8, pfNativeError, szErrorMsg8, 3*cbErrorMsgMax+1, &pcbErrorMsg8);
|
|
if (result == SQL_SUCCESS) {
|
|
size_t l=6, z=6*sizeof(SQLWCHAR);
|
|
ascii2unicode((char*)szSqlState8, &l, (char*)szSqlState, &z);
|
|
l = cbErrorMsgMax;
|
|
ascii2unicode((char*)szErrorMsg8, (size_t*)&pcbErrorMsg8, (char*)szErrorMsg, &l);
|
|
if (pcbErrorMsg)
|
|
*pcbErrorMsg = l;
|
|
}
|
|
return result;
|
|
}
|
|
#endif // ENABLE_ODBC_W
|
|
|
|
SQLRETURN SQL_API SQLExecute(SQLHSTMT hstmt)
|
|
{
|
|
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
|
|
|
TRACE("SQLExecute");
|
|
|
|
/* fprintf(stderr,"query = %s\n",stmt->query); */
|
|
_odbc_fix_literals(stmt);
|
|
|
|
mdb_sql_reset(stmt->sql);
|
|
|
|
mdb_sql_run_query(stmt->sql, stmt->query);
|
|
if (mdb_sql_has_error(stmt->sql)) {
|
|
LogError("Couldn't parse SQL\n");
|
|
mdb_sql_reset(stmt->sql);
|
|
return SQL_ERROR;
|
|
} else {
|
|
return SQL_SUCCESS;
|
|
}
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLExecDirect(
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szSqlStr,
|
|
SQLINTEGER cbSqlStr)
|
|
{
|
|
SQLPrepare(hstmt, szSqlStr, cbSqlStr);
|
|
return SQLExecute(hstmt);
|
|
}
|
|
|
|
#ifdef ENABLE_ODBC_W
|
|
SQLRETURN SQL_API SQLExecDirectW(
|
|
SQLHSTMT hstmt,
|
|
SQLWCHAR *szSqlStr,
|
|
SQLINTEGER cbSqlStr)
|
|
{
|
|
TRACE("SQLExecDirectW");
|
|
if(cbSqlStr==SQL_NTS)cbSqlStr=sqlwlen(szSqlStr);
|
|
{
|
|
SQLCHAR *tmp=calloc(cbSqlStr*4,1);
|
|
size_t l=cbSqlStr*4,z=cbSqlStr*2;
|
|
SQLRETURN ret;
|
|
unicode2ascii((char*)szSqlStr, &z, (char*)tmp, &l);
|
|
ret = SQLExecDirect(hstmt, tmp, l);
|
|
TRACE("SQLExecDirectW end");
|
|
free(tmp);
|
|
return ret;
|
|
}
|
|
}
|
|
#endif // ENABLE_ODBC_W
|
|
|
|
static void
|
|
bind_columns(struct _hstmt *stmt)
|
|
{
|
|
struct _sql_bind_info *cur;
|
|
|
|
TRACE("bind_columns");
|
|
|
|
if (stmt->rows_affected==0) {
|
|
cur = stmt->bind_head;
|
|
while (cur) {
|
|
if (cur->column_number>0 &&
|
|
cur->column_number <= stmt->sql->num_columns) {
|
|
mdb_sql_bind_column(stmt->sql, cur->column_number,
|
|
cur->varaddr, cur->column_lenbind);
|
|
} else {
|
|
/* log error ? */
|
|
}
|
|
cur = cur->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
unbind_columns(struct _hstmt *stmt)
|
|
{
|
|
struct _sql_bind_info *cur, *next;
|
|
|
|
TRACE("unbind_columns");
|
|
|
|
//Free the memory allocated for bound columns
|
|
cur = stmt->bind_head;
|
|
while(cur) {
|
|
next = cur->next;
|
|
g_free(cur);
|
|
cur = next;
|
|
}
|
|
stmt->bind_head = NULL;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLFetch(
|
|
SQLHSTMT hstmt)
|
|
{
|
|
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
|
|
|
TRACE("SQLFetch");
|
|
/* if we bound columns, transfer them to res_info now that we have one */
|
|
bind_columns(stmt);
|
|
//cur = stmt->bind_head;
|
|
//while (cur) {
|
|
//if (cur->column_number>0 &&
|
|
//cur->column_number <= stmt->sql->num_columns) {
|
|
// if (cur->column_lenbind) *(cur->column_lenbind) = 4;
|
|
//}
|
|
//cur = cur->next;
|
|
//}
|
|
if ( stmt->sql->limit >= 0 && stmt->rows_affected == stmt->sql->limit ) {
|
|
return SQL_NO_DATA_FOUND;
|
|
}
|
|
|
|
if (mdb_fetch_row(stmt->sql->cur_table)) {
|
|
stmt->rows_affected++;
|
|
stmt->pos=0;
|
|
return SQL_SUCCESS;
|
|
} else {
|
|
return SQL_NO_DATA_FOUND;
|
|
}
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLFreeConnect(
|
|
SQLHDBC hdbc)
|
|
{
|
|
struct _hdbc* dbc = (struct _hdbc*) hdbc;
|
|
struct _henv* env;
|
|
|
|
TRACE("SQLFreeConnect");
|
|
|
|
env = dbc->henv;
|
|
|
|
if (dbc->statements->len) {
|
|
// Function sequence error
|
|
strcpy(sqlState, "HY010");
|
|
return SQL_ERROR;
|
|
}
|
|
if (!g_ptr_array_remove(env->connections, dbc))
|
|
return SQL_INVALID_HANDLE;
|
|
|
|
FreeConnectParams(dbc->params);
|
|
g_ptr_array_free(dbc->statements, TRUE);
|
|
mdb_sql_exit(dbc->sqlconn);
|
|
g_free(dbc);
|
|
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLFreeEnv(
|
|
SQLHENV henv)
|
|
{
|
|
struct _henv* env = (struct _henv*)henv;
|
|
|
|
TRACE("SQLFreeEnv");
|
|
|
|
if (env->connections->len) {
|
|
// Function sequence error
|
|
strcpy(sqlState, "HY010");
|
|
return SQL_ERROR;
|
|
}
|
|
g_ptr_array_free(env->connections, TRUE);
|
|
g_free(env);
|
|
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLFreeStmt(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT fOption)
|
|
{
|
|
struct _hstmt *stmt=(struct _hstmt *)hstmt;
|
|
struct _hdbc *dbc = (struct _hdbc *) stmt->hdbc;
|
|
|
|
TRACE("SQLFreeStmt");
|
|
if (fOption==SQL_DROP) {
|
|
if (!g_ptr_array_remove(dbc->statements, stmt))
|
|
return SQL_INVALID_HANDLE;
|
|
mdb_sql_exit(stmt->sql);
|
|
unbind_columns(stmt);
|
|
g_free(stmt);
|
|
} else if (fOption==SQL_CLOSE) {
|
|
stmt->rows_affected = 0;
|
|
} else if (fOption==SQL_UNBIND) {
|
|
unbind_columns(stmt);
|
|
} else if (fOption==SQL_RESET_PARAMS) {
|
|
/* Bound parameters not currently implemented */
|
|
} else {
|
|
}
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLFreeHandle(
|
|
SQLSMALLINT HandleType,
|
|
SQLHANDLE Handle)
|
|
{
|
|
SQLRETURN retval = SQL_ERROR;
|
|
TRACE("SQLFreeHandle");
|
|
switch(HandleType) {
|
|
case SQL_HANDLE_STMT:
|
|
retval = SQLFreeStmt(Handle,SQL_DROP);
|
|
break;
|
|
case SQL_HANDLE_DBC:
|
|
retval = SQLFreeConnect(Handle);
|
|
break;
|
|
case SQL_HANDLE_ENV:
|
|
retval = SQLFreeEnv(Handle);
|
|
break;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLGetStmtAttr (
|
|
SQLHSTMT StatementHandle,
|
|
SQLINTEGER Attribute,
|
|
SQLPOINTER Value,
|
|
SQLINTEGER BufferLength,
|
|
SQLINTEGER * StringLength)
|
|
{
|
|
TRACE("SQLGetStmtAttr");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLGetCursorName(
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szCursor,
|
|
SQLSMALLINT cbCursorMax,
|
|
SQLSMALLINT *pcbCursor)
|
|
{
|
|
TRACE("SQLGetCursorName");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLNumResultCols(
|
|
SQLHSTMT hstmt,
|
|
SQLSMALLINT *pccol)
|
|
{
|
|
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
|
|
|
TRACE("SQLNumResultCols");
|
|
*pccol = stmt->sql->num_columns;
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLPrepare(
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szSqlStr,
|
|
SQLINTEGER cbSqlStr)
|
|
{
|
|
struct _hstmt *stmt=(struct _hstmt *)hstmt;
|
|
int sqllen = _odbc_get_string_size(cbSqlStr, szSqlStr);
|
|
|
|
TRACE("SQLPrepare");
|
|
|
|
strncpy(stmt->query, (char*)szSqlStr, sqllen);
|
|
stmt->query[sqllen]='\0';
|
|
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLRowCount(
|
|
SQLHSTMT hstmt,
|
|
SQLLEN *pcrow)
|
|
{
|
|
struct _hstmt *stmt=(struct _hstmt *)hstmt;
|
|
|
|
TRACE("SQLRowCount");
|
|
*pcrow = stmt->rows_affected;
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLSetCursorName(
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szCursor,
|
|
SQLSMALLINT cbCursor)
|
|
{
|
|
TRACE("SQLSetCursorName");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLTransact(
|
|
SQLHENV henv,
|
|
SQLHDBC hdbc,
|
|
SQLUSMALLINT fType)
|
|
{
|
|
TRACE("SQLTransact");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
|
|
SQLRETURN SQL_API SQLSetParam( /* Use SQLBindParameter */
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT ipar,
|
|
SQLSMALLINT fCType,
|
|
SQLSMALLINT fSqlType,
|
|
SQLULEN cbParamDef,
|
|
SQLSMALLINT ibScale,
|
|
SQLPOINTER rgbValue,
|
|
SQLLEN *pcbValue)
|
|
{
|
|
TRACE("SQLSetParam");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLColumns(
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szCatalogName,
|
|
SQLSMALLINT cbCatalogName,
|
|
SQLCHAR *szSchemaName,
|
|
SQLSMALLINT cbSchemaName,
|
|
SQLCHAR *szTableName,
|
|
SQLSMALLINT cbTableName,
|
|
SQLCHAR *szColumnName,
|
|
SQLSMALLINT cbColumnName)
|
|
{
|
|
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
|
MdbSQL *sql = stmt->sql;
|
|
MdbHandle *mdb = sql->mdb;
|
|
MdbTableDef *ttable;
|
|
MdbField fields[18];
|
|
unsigned char row_buffer[MDB_PGSIZE];
|
|
int row_size;
|
|
unsigned int i, j, k;
|
|
MdbCatalogEntry *entry;
|
|
MdbTableDef *table;
|
|
MdbColumn *col;
|
|
unsigned int ts2, ts3, ts5;
|
|
unsigned char t2[MDB_BIND_SIZE],
|
|
t3[MDB_BIND_SIZE],
|
|
t5[MDB_BIND_SIZE];
|
|
SQLSMALLINT nullable; /* SQL_NULLABLE or SQL_NO_NULLS */
|
|
SQLSMALLINT datatype; /* For datetime, use concise data type */
|
|
SQLSMALLINT sqldatatype; /* For datetime, use nonconcise data type */
|
|
SQLINTEGER ordinal;
|
|
|
|
TRACE("SQLColumns");
|
|
|
|
mdb_read_catalog(mdb, MDB_ANY);
|
|
|
|
ttable = mdb_create_temp_table(mdb, "#columns");
|
|
mdb_sql_add_temp_col(sql, ttable, 0, "TABLE_CAT", MDB_TEXT, 128, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 1, "TABLE_SCHEM", MDB_TEXT, 128, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 2, "TABLE_NAME", MDB_TEXT, 128, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 3, "COLUMN_NAME", MDB_TEXT, 128, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 4, "DATA_TYPE", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 5, "TYPE_NAME", MDB_TEXT, 128, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 6, "COLUMN_SIZE", MDB_LONGINT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 7, "BUFFER_LENGTH", MDB_LONGINT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 8, "DECIMAL_DIGITS", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 9, "NUM_PREC_RADIX", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 10, "NULLABLE", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 11, "REMARKS", MDB_TEXT, 254, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 12, "COLUMN_DEF", MDB_TEXT, 254, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 13, "SQL_DATA_TYPE", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 14, "SQL_DATETIME_SUB", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 15, "CHAR_OCTET_LENGTH", MDB_LONGINT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 16, "ORDINAL_POSITION", MDB_LONGINT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 17, "IS_NULLABLE", MDB_TEXT, 254, 0);
|
|
mdb_temp_columns_end(ttable);
|
|
|
|
for (i=0; i<mdb->num_catalog; i++) {
|
|
entry = g_ptr_array_index(mdb->catalog, i);
|
|
/* TODO: Do more advanced matching */
|
|
if (entry->object_type != MDB_TABLE || g_ascii_strcasecmp((char*)szTableName, entry->object_name) != 0)
|
|
continue;
|
|
table = mdb_read_table(entry);
|
|
if ( !table )
|
|
{
|
|
LogError ("Could not read table '%s'", szTableName);
|
|
return SQL_ERROR;
|
|
}
|
|
mdb_read_columns(table);
|
|
for (j=0; j<table->num_cols; j++) {
|
|
col = g_ptr_array_index(table->columns, j);
|
|
|
|
ts2 = mdb_ascii2unicode(mdb, table->name, 0, (char*)t2, MDB_BIND_SIZE);
|
|
ts3 = mdb_ascii2unicode(mdb, col->name, 0, (char*)t3, MDB_BIND_SIZE);
|
|
ts5 = mdb_ascii2unicode(mdb, _odbc_get_client_type_name(col), 0, (char*)t5, MDB_BIND_SIZE);
|
|
|
|
nullable = SQL_NO_NULLS;
|
|
datatype = _odbc_get_client_type(col);
|
|
sqldatatype = _odbc_get_client_type(col);
|
|
ordinal = j+1;
|
|
|
|
/* Set all fields to NULL */
|
|
for (k=0; k<18; k++) {
|
|
FILL_FIELD(&fields[k], NULL, 0);
|
|
}
|
|
|
|
FILL_FIELD(&fields[2], t2, ts2);
|
|
FILL_FIELD(&fields[3], t3, ts3);
|
|
FILL_FIELD(&fields[4], &datatype, 0);
|
|
FILL_FIELD(&fields[5], t5, ts5);
|
|
FILL_FIELD(&fields[10], &nullable, 0);
|
|
FILL_FIELD(&fields[13], &sqldatatype, 0);
|
|
FILL_FIELD(&fields[16], &ordinal, 0);
|
|
|
|
row_size = mdb_pack_row(ttable, row_buffer, 18, fields);
|
|
mdb_add_row_to_pg(ttable, row_buffer, row_size);
|
|
ttable->num_rows++;
|
|
}
|
|
mdb_free_tabledef(table);
|
|
}
|
|
sql->cur_table = ttable;
|
|
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
#ifdef ENABLE_ODBC_W
|
|
SQLRETURN SQL_API SQLColumnsW(
|
|
SQLHSTMT hstmt,
|
|
SQLWCHAR *szCatalogName,
|
|
SQLSMALLINT cbCatalogName,
|
|
SQLWCHAR *szSchemaName,
|
|
SQLSMALLINT cbSchemaName,
|
|
SQLWCHAR *szTableName,
|
|
SQLSMALLINT cbTableName,
|
|
SQLWCHAR *szColumnName,
|
|
SQLSMALLINT cbColumnName)
|
|
{
|
|
if(cbTableName==SQL_NTS)cbTableName=sqlwlen(szTableName);
|
|
{
|
|
SQLCHAR *tmp=calloc(cbTableName*4,1);
|
|
size_t l=cbTableName*4,z=cbTableName*2;
|
|
SQLRETURN ret;
|
|
unicode2ascii((char*)szTableName, &z, (char*)tmp, &l);
|
|
ret = SQLColumns(hstmt, NULL, 0, NULL, 0, tmp, l, NULL, 0);
|
|
free(tmp);
|
|
return ret;
|
|
}
|
|
}
|
|
#endif //ENABLE_ODBC_W
|
|
|
|
SQLRETURN SQL_API SQLGetConnectOption(
|
|
SQLHDBC hdbc,
|
|
SQLUSMALLINT fOption,
|
|
SQLPOINTER pvParam)
|
|
{
|
|
TRACE("SQLGetConnectOption");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLGetData(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT icol,
|
|
SQLSMALLINT fCType,
|
|
SQLPOINTER rgbValue,
|
|
SQLLEN cbValueMax,
|
|
SQLLEN *pcbValue)
|
|
{
|
|
struct _hstmt *stmt;
|
|
MdbSQL *sql;
|
|
MdbHandle *mdb;
|
|
MdbSQLColumn *sqlcol;
|
|
MdbColumn *col;
|
|
MdbTableDef *table;
|
|
int i, intValue;
|
|
|
|
TRACE("SQLGetData");
|
|
stmt = (struct _hstmt *) hstmt;
|
|
sql = stmt->sql;
|
|
mdb = sql->mdb;
|
|
|
|
if (icol<1 || icol>sql->num_columns) {
|
|
strcpy(sqlState, "07009");
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
sqlcol = g_ptr_array_index(sql->columns,icol - 1);
|
|
table = sql->cur_table;
|
|
for (i=0;i<table->num_cols;i++) {
|
|
col=g_ptr_array_index(table->columns,i);
|
|
if (!g_ascii_strcasecmp(sqlcol->name, col->name)) {
|
|
break;
|
|
}
|
|
}
|
|
if (i==table->num_cols)
|
|
return SQL_ERROR;
|
|
|
|
if (icol!=stmt->icol) {
|
|
stmt->icol=icol;
|
|
stmt->pos=0;
|
|
}
|
|
|
|
if (!rgbValue) {
|
|
strcpy(sqlState, "HY009");
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
if (col->col_type == MDB_BOOL) {
|
|
// bool cannot be null
|
|
*(BOOL*)rgbValue = col->cur_value_len ? 0 : 1;
|
|
if (pcbValue)
|
|
*pcbValue = 1;
|
|
return SQL_SUCCESS;
|
|
}
|
|
if (col->cur_value_len == 0) {
|
|
/* When NULL data is retrieved, non-null pcbValue is
|
|
required */
|
|
if (!pcbValue) {
|
|
strcpy(sqlState, "22002");
|
|
return SQL_ERROR;
|
|
}
|
|
*pcbValue = SQL_NULL_DATA;
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
if (fCType==SQL_ARD_TYPE) {
|
|
// Get _sql_bind_info
|
|
struct _sql_bind_info *cur;
|
|
for (cur = stmt->bind_head; cur; cur=cur->next) {
|
|
if (cur->column_number == icol) {
|
|
fCType = cur->column_bindtype;
|
|
goto found_bound_type;
|
|
}
|
|
}
|
|
strcpy(sqlState, "07009");
|
|
return SQL_ERROR;
|
|
}
|
|
found_bound_type:
|
|
if (fCType==SQL_C_DEFAULT)
|
|
fCType = _odbc_get_client_type(col);
|
|
if (fCType == SQL_C_CHAR)
|
|
goto to_c_char;
|
|
switch(col->col_type) {
|
|
case MDB_BYTE:
|
|
intValue = (int)mdb_get_byte(mdb->pg_buf, col->cur_value_start);
|
|
goto to_integer_type;
|
|
case MDB_INT:
|
|
intValue = mdb_get_int16(mdb->pg_buf, col->cur_value_start);
|
|
goto to_integer_type;
|
|
case MDB_LONGINT:
|
|
intValue = mdb_get_int32(mdb->pg_buf, col->cur_value_start);
|
|
goto to_integer_type;
|
|
to_integer_type:
|
|
switch (fCType) {
|
|
case SQL_C_UTINYINT:
|
|
if (intValue<0 || intValue>UCHAR_MAX) {
|
|
strcpy(sqlState, "22003"); // Numeric value out of range
|
|
return SQL_ERROR;
|
|
}
|
|
*(SQLCHAR*)rgbValue = (SQLCHAR)intValue;
|
|
if (pcbValue)
|
|
*pcbValue = sizeof(SQLCHAR);
|
|
break;
|
|
case SQL_C_TINYINT:
|
|
case SQL_C_STINYINT:
|
|
if (intValue<SCHAR_MIN || intValue>SCHAR_MAX) {
|
|
strcpy(sqlState, "22003"); // Numeric value out of range
|
|
return SQL_ERROR;
|
|
}
|
|
*(SQLSCHAR*)rgbValue = (SQLSCHAR)intValue;
|
|
if (pcbValue)
|
|
*pcbValue = sizeof(SQLSCHAR);
|
|
break;
|
|
case SQL_C_USHORT:
|
|
case SQL_C_SHORT:
|
|
if (intValue<0 || intValue>USHRT_MAX) {
|
|
strcpy(sqlState, "22003"); // Numeric value out of range
|
|
return SQL_ERROR;
|
|
}
|
|
*(SQLSMALLINT*)rgbValue = (SQLSMALLINT)intValue;
|
|
if (pcbValue)
|
|
*pcbValue = sizeof(SQLSMALLINT);
|
|
break;
|
|
case SQL_C_SSHORT:
|
|
if (intValue<SHRT_MIN || intValue>SHRT_MAX) {
|
|
strcpy(sqlState, "22003"); // Numeric value out of range
|
|
return SQL_ERROR;
|
|
}
|
|
*(SQLSMALLINT*)rgbValue = (SQLSMALLINT)intValue;
|
|
if (pcbValue)
|
|
*pcbValue = sizeof(SQLSMALLINT);
|
|
break;
|
|
case SQL_C_ULONG:
|
|
if (intValue<0 || intValue>UINT_MAX) {
|
|
strcpy(sqlState, "22003"); // Numeric value out of range
|
|
return SQL_ERROR;
|
|
}
|
|
*(SQLUINTEGER*)rgbValue = (SQLINTEGER)intValue;
|
|
if (pcbValue)
|
|
*pcbValue = sizeof(SQLINTEGER);
|
|
break;
|
|
case SQL_C_LONG:
|
|
case SQL_C_SLONG:
|
|
if (intValue<INT_MIN || intValue>INT_MAX) {
|
|
strcpy(sqlState, "22003"); // Numeric value out of range
|
|
return SQL_ERROR;
|
|
}
|
|
*(SQLINTEGER*)rgbValue = intValue;
|
|
if (pcbValue)
|
|
*pcbValue = sizeof(SQLINTEGER);
|
|
break;
|
|
default:
|
|
strcpy(sqlState, "HYC00"); // Not implemented
|
|
return SQL_ERROR;
|
|
}
|
|
break;
|
|
// case MDB_MONEY: TODO
|
|
case MDB_FLOAT:
|
|
*(float*)rgbValue = mdb_get_single(mdb->pg_buf, col->cur_value_start);
|
|
if (pcbValue)
|
|
*pcbValue = sizeof(float);
|
|
break;
|
|
case MDB_DOUBLE:
|
|
*(double*)rgbValue = mdb_get_double(mdb->pg_buf, col->cur_value_start);
|
|
if (pcbValue)
|
|
*pcbValue = sizeof(double);
|
|
break;
|
|
#if ODBCVER >= 0x0300
|
|
// returns text if old odbc
|
|
case MDB_DATETIME:
|
|
{
|
|
struct tm tmp_t;
|
|
mdb_date_to_tm(mdb_get_double(mdb->pg_buf, col->cur_value_start), &tmp_t);
|
|
|
|
const char *format = mdb_col_get_prop(col, "Format");
|
|
if (format && !strcmp(format, "Short Date")) {
|
|
DATE_STRUCT sql_dt;
|
|
sql_dt.year = tmp_t.tm_year + 1900;
|
|
sql_dt.month = tmp_t.tm_mon + 1;
|
|
sql_dt.day = tmp_t.tm_mday;
|
|
*(DATE_STRUCT*)rgbValue = sql_dt;
|
|
if (pcbValue)
|
|
*pcbValue = sizeof(DATE_STRUCT);
|
|
} else {
|
|
TIMESTAMP_STRUCT sql_ts;
|
|
sql_ts.year = tmp_t.tm_year + 1900;
|
|
sql_ts.month = tmp_t.tm_mon + 1;
|
|
sql_ts.day = tmp_t.tm_mday;
|
|
sql_ts.hour = tmp_t.tm_hour;
|
|
sql_ts.minute = tmp_t.tm_min;
|
|
sql_ts.second = tmp_t.tm_sec;
|
|
sql_ts.fraction = 0;
|
|
|
|
*(TIMESTAMP_STRUCT*)rgbValue = sql_ts;
|
|
if (pcbValue)
|
|
*pcbValue = sizeof(TIMESTAMP_STRUCT);
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
default: /* FIXME here we assume fCType == SQL_C_CHAR */
|
|
to_c_char:
|
|
{
|
|
static __thread size_t len = 0;
|
|
static __thread char *str = NULL;
|
|
|
|
if (col->col_type == MDB_OLE) {
|
|
if (stmt->pos == 0) {
|
|
str = mdb_ole_read_full(mdb, col, &len);
|
|
}
|
|
} else {
|
|
str = mdb_col_to_string(mdb, mdb->pg_buf,
|
|
col->cur_value_start, col->col_type, col->cur_value_len);
|
|
len = strlen(str);
|
|
}
|
|
|
|
if (stmt->pos >= len) {
|
|
free(str);
|
|
str = NULL;
|
|
return SQL_NO_DATA;
|
|
}
|
|
if (cbValueMax < 0) {
|
|
strcpy(sqlState, "HY090"); // Invalid string or buffer length
|
|
free(str);
|
|
str = NULL;
|
|
return SQL_ERROR;
|
|
}
|
|
if (pcbValue) {
|
|
*pcbValue = len + 1 - stmt->pos;
|
|
}
|
|
if (cbValueMax == 0) {
|
|
free(str);
|
|
str = NULL;
|
|
return SQL_SUCCESS_WITH_INFO;
|
|
}
|
|
|
|
/* if the column type is OLE, then we don't add terminators
|
|
see https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlgetdata-function?view=sql-server-ver15
|
|
and https://www.ibm.com/support/knowledgecenter/SSEPEK_11.0.0/odbc/src/tpc/db2z_fngetdata.html
|
|
|
|
"The buffer that the rgbValue argument specifies contains nul-terminated values, unless you retrieve
|
|
binary data, or the SQL data type of the column is graphic (DBCS) and the C buffer type is SQL_C_CHAR."
|
|
*/
|
|
const int needsTerminator = (col->col_type != MDB_OLE);
|
|
|
|
const int totalSizeRemaining = len - stmt->pos;
|
|
const int partsRemain = cbValueMax - ( needsTerminator ? 1 : 0 ) < totalSizeRemaining;
|
|
const int sizeToReadThisPart = partsRemain ? cbValueMax - ( needsTerminator ? 1 : 0 ) : totalSizeRemaining;
|
|
memcpy(rgbValue, str + stmt->pos, sizeToReadThisPart);
|
|
|
|
if (needsTerminator)
|
|
{
|
|
((char *)rgbValue)[sizeToReadThisPart] = '\0';
|
|
}
|
|
if (partsRemain) {
|
|
stmt->pos += cbValueMax - ( needsTerminator ? 1 : 0 );
|
|
if (col->col_type != MDB_OLE) { free(str); str = NULL; }
|
|
strcpy(sqlState, "01004"); // truncated
|
|
return SQL_SUCCESS_WITH_INFO;
|
|
}
|
|
stmt->pos = len;
|
|
free(str);
|
|
str = NULL;
|
|
break;
|
|
}
|
|
}
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
#ifdef ENABLE_ODBC_W
|
|
SQLRETURN SQL_API SQLGetDataW(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT icol,
|
|
SQLSMALLINT fCType,
|
|
SQLPOINTER rgbValue,
|
|
SQLLEN cbValueMax,
|
|
SQLLEN *pcbValue)
|
|
{
|
|
//todo: treat numbers correctly
|
|
|
|
SQLCHAR *tmp=calloc(cbValueMax*4,1);
|
|
size_t l=cbValueMax*4;
|
|
SQLRETURN ret = SQLGetData(hstmt, icol, fCType, tmp, cbValueMax*4, (SQLLEN*)&l);
|
|
ascii2unicode((char*)tmp, &l, (char*)rgbValue, (size_t*)pcbValue);
|
|
*pcbValue/=sizeof(SQLWCHAR);
|
|
free(tmp);
|
|
return ret;
|
|
}
|
|
#endif //ENABLE_ODBC_W
|
|
|
|
static void _set_func_exists(SQLUSMALLINT *pfExists, SQLUSMALLINT fFunction)
|
|
{
|
|
SQLUSMALLINT *mod;
|
|
mod = pfExists + (fFunction >> 4);
|
|
*mod |= (1 << (fFunction & 0x0f));
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLGetFunctions(
|
|
SQLHDBC hdbc,
|
|
SQLUSMALLINT fFunction,
|
|
SQLUSMALLINT *pfExists)
|
|
{
|
|
|
|
TRACE("SQLGetFunctions");
|
|
switch (fFunction) {
|
|
#if ODBCVER >= 0x0300
|
|
case SQL_API_ODBC3_ALL_FUNCTIONS:
|
|
memset(pfExists, 0, SQL_API_ODBC3_ALL_FUNCTIONS_SIZE);
|
|
_set_func_exists(pfExists,SQL_API_SQLALLOCCONNECT);
|
|
_set_func_exists(pfExists,SQL_API_SQLALLOCENV);
|
|
_set_func_exists(pfExists,SQL_API_SQLALLOCHANDLE);
|
|
_set_func_exists(pfExists,SQL_API_SQLALLOCSTMT);
|
|
_set_func_exists(pfExists,SQL_API_SQLBINDCOL);
|
|
_set_func_exists(pfExists,SQL_API_SQLBINDPARAMETER);
|
|
_set_func_exists(pfExists,SQL_API_SQLCANCEL);
|
|
//_set_func_exists(pfExists,SQL_API_SQLCLOSECURSOR);
|
|
_set_func_exists(pfExists,SQL_API_SQLCOLATTRIBUTE);
|
|
_set_func_exists(pfExists,SQL_API_SQLCOLUMNS);
|
|
_set_func_exists(pfExists,SQL_API_SQLCONNECT);
|
|
//_set_func_exists(pfExists,SQL_API_SQLCOPYDESC);
|
|
_set_func_exists(pfExists,SQL_API_SQLDATASOURCES);
|
|
_set_func_exists(pfExists,SQL_API_SQLDESCRIBECOL);
|
|
_set_func_exists(pfExists,SQL_API_SQLDISCONNECT);
|
|
//_set_func_exists(pfExists,SQL_API_SQLENDTRAN);
|
|
_set_func_exists(pfExists,SQL_API_SQLERROR);
|
|
_set_func_exists(pfExists,SQL_API_SQLEXECDIRECT);
|
|
_set_func_exists(pfExists,SQL_API_SQLEXECUTE);
|
|
_set_func_exists(pfExists,SQL_API_SQLFETCH);
|
|
//_set_func_exists(pfExists,SQL_API_SQLFETCHSCROLL);
|
|
_set_func_exists(pfExists,SQL_API_SQLFREECONNECT);
|
|
_set_func_exists(pfExists,SQL_API_SQLFREEENV);
|
|
_set_func_exists(pfExists,SQL_API_SQLFREEHANDLE);
|
|
_set_func_exists(pfExists,SQL_API_SQLFREESTMT);
|
|
//_set_func_exists(pfExists,SQL_API_SQLGETCONNECTATTR);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETCONNECTOPTION);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETCURSORNAME);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETDATA);
|
|
//_set_func_exists(pfExists,SQL_API_SQLGETDESCFIELD);
|
|
//_set_func_exists(pfExists,SQL_API_SQLGETDESCREC);
|
|
//_set_func_exists(pfExists,SQL_API_SQLGETDIAGFIELD);
|
|
//_set_func_exists(pfExists,SQL_API_SQLGETDIAGREC);
|
|
//_set_func_exists(pfExists,SQL_API_SQLGETENVATTR);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETFUNCTIONS);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETINFO);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETSTMTATTR);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETSTMTOPTION);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETTYPEINFO);
|
|
_set_func_exists(pfExists,SQL_API_SQLNUMRESULTCOLS);
|
|
_set_func_exists(pfExists,SQL_API_SQLPARAMDATA);
|
|
_set_func_exists(pfExists,SQL_API_SQLPREPARE);
|
|
_set_func_exists(pfExists,SQL_API_SQLPUTDATA);
|
|
_set_func_exists(pfExists,SQL_API_SQLROWCOUNT);
|
|
//_set_func_exists(pfExists,SQL_API_SQLSETCONNECTATTR);
|
|
_set_func_exists(pfExists,SQL_API_SQLSETCONNECTOPTION);
|
|
_set_func_exists(pfExists,SQL_API_SQLSETCURSORNAME);
|
|
//_set_func_exists(pfExists,SQL_API_SQLSETDESCFIELD);
|
|
//_set_func_exists(pfExists,SQL_API_SQLSETDESCREC);
|
|
_set_func_exists(pfExists,SQL_API_SQLSETENVATTR);
|
|
_set_func_exists(pfExists,SQL_API_SQLSETPARAM);
|
|
//_set_func_exists(pfExists,SQL_API_SQLSETSTMTATTR);
|
|
_set_func_exists(pfExists,SQL_API_SQLSETSTMTOPTION);
|
|
_set_func_exists(pfExists,SQL_API_SQLSPECIALCOLUMNS);
|
|
_set_func_exists(pfExists,SQL_API_SQLSTATISTICS);
|
|
_set_func_exists(pfExists,SQL_API_SQLTABLES);
|
|
_set_func_exists(pfExists,SQL_API_SQLTRANSACT);
|
|
break;
|
|
#endif
|
|
case SQL_API_ALL_FUNCTIONS:
|
|
memset(pfExists, 0, 100); // 100 by spec
|
|
_set_func_exists(pfExists,SQL_API_SQLALLOCCONNECT);
|
|
_set_func_exists(pfExists,SQL_API_SQLALLOCENV);
|
|
_set_func_exists(pfExists,SQL_API_SQLALLOCSTMT);
|
|
_set_func_exists(pfExists,SQL_API_SQLBINDCOL);
|
|
_set_func_exists(pfExists,SQL_API_SQLCANCEL);
|
|
_set_func_exists(pfExists,SQL_API_SQLCOLATTRIBUTE);
|
|
_set_func_exists(pfExists,SQL_API_SQLCOLUMNS);
|
|
_set_func_exists(pfExists,SQL_API_SQLCONNECT);
|
|
_set_func_exists(pfExists,SQL_API_SQLDATASOURCES);
|
|
_set_func_exists(pfExists,SQL_API_SQLDESCRIBECOL);
|
|
_set_func_exists(pfExists,SQL_API_SQLDISCONNECT);
|
|
_set_func_exists(pfExists,SQL_API_SQLERROR);
|
|
_set_func_exists(pfExists,SQL_API_SQLEXECDIRECT);
|
|
_set_func_exists(pfExists,SQL_API_SQLEXECUTE);
|
|
_set_func_exists(pfExists,SQL_API_SQLFETCH);
|
|
_set_func_exists(pfExists,SQL_API_SQLFREECONNECT);
|
|
_set_func_exists(pfExists,SQL_API_SQLFREEENV);
|
|
_set_func_exists(pfExists,SQL_API_SQLFREEHANDLE);
|
|
_set_func_exists(pfExists,SQL_API_SQLFREESTMT);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETCONNECTOPTION);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETCURSORNAME);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETDATA);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETFUNCTIONS);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETINFO);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETSTMTATTR);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETSTMTOPTION);
|
|
_set_func_exists(pfExists,SQL_API_SQLGETTYPEINFO);
|
|
_set_func_exists(pfExists,SQL_API_SQLNUMRESULTCOLS);
|
|
_set_func_exists(pfExists,SQL_API_SQLPARAMDATA);
|
|
_set_func_exists(pfExists,SQL_API_SQLPREPARE);
|
|
_set_func_exists(pfExists,SQL_API_SQLPUTDATA);
|
|
_set_func_exists(pfExists,SQL_API_SQLROWCOUNT);
|
|
_set_func_exists(pfExists,SQL_API_SQLSETCONNECTOPTION);
|
|
_set_func_exists(pfExists,SQL_API_SQLSETCURSORNAME);
|
|
_set_func_exists(pfExists,SQL_API_SQLSETENVATTR);
|
|
_set_func_exists(pfExists,SQL_API_SQLSETPARAM);
|
|
_set_func_exists(pfExists,SQL_API_SQLSETSTMTOPTION);
|
|
_set_func_exists(pfExists,SQL_API_SQLSPECIALCOLUMNS);
|
|
_set_func_exists(pfExists,SQL_API_SQLSTATISTICS);
|
|
_set_func_exists(pfExists,SQL_API_SQLTABLES);
|
|
_set_func_exists(pfExists,SQL_API_SQLTRANSACT);
|
|
break;
|
|
|
|
case SQL_API_SQLALLOCCONNECT:
|
|
case SQL_API_SQLALLOCENV:
|
|
case SQL_API_SQLALLOCSTMT:
|
|
case SQL_API_SQLBINDCOL:
|
|
case SQL_API_SQLCANCEL:
|
|
case SQL_API_SQLCOLATTRIBUTE:
|
|
case SQL_API_SQLCOLUMNS:
|
|
case SQL_API_SQLCONNECT:
|
|
case SQL_API_SQLDATASOURCES:
|
|
case SQL_API_SQLDESCRIBECOL:
|
|
case SQL_API_SQLDISCONNECT:
|
|
case SQL_API_SQLERROR:
|
|
case SQL_API_SQLEXECDIRECT:
|
|
case SQL_API_SQLEXECUTE:
|
|
case SQL_API_SQLFETCH:
|
|
case SQL_API_SQLFREECONNECT:
|
|
case SQL_API_SQLFREEENV:
|
|
case SQL_API_SQLFREEHANDLE:
|
|
case SQL_API_SQLFREESTMT:
|
|
case SQL_API_SQLGETCONNECTOPTION:
|
|
case SQL_API_SQLGETCURSORNAME:
|
|
case SQL_API_SQLGETDATA:
|
|
case SQL_API_SQLGETFUNCTIONS:
|
|
case SQL_API_SQLGETINFO:
|
|
case SQL_API_SQLGETSTMTATTR:
|
|
case SQL_API_SQLGETSTMTOPTION:
|
|
case SQL_API_SQLGETTYPEINFO:
|
|
case SQL_API_SQLNUMRESULTCOLS:
|
|
case SQL_API_SQLPARAMDATA:
|
|
case SQL_API_SQLPREPARE:
|
|
case SQL_API_SQLPUTDATA:
|
|
case SQL_API_SQLROWCOUNT:
|
|
case SQL_API_SQLSETCONNECTOPTION:
|
|
case SQL_API_SQLSETCURSORNAME:
|
|
case SQL_API_SQLSETENVATTR:
|
|
case SQL_API_SQLSETPARAM:
|
|
case SQL_API_SQLSETSTMTOPTION:
|
|
case SQL_API_SQLSPECIALCOLUMNS:
|
|
case SQL_API_SQLSTATISTICS:
|
|
case SQL_API_SQLTABLES:
|
|
case SQL_API_SQLTRANSACT:
|
|
*pfExists = 1; /* SQL_TRUE */
|
|
break;
|
|
|
|
default:
|
|
*pfExists = 0; /* SQL_FALSE */
|
|
break;
|
|
}
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLGetInfo(
|
|
SQLHDBC hdbc,
|
|
SQLUSMALLINT fInfoType,
|
|
SQLPOINTER rgbInfoValue,
|
|
SQLSMALLINT cbInfoValueMax,
|
|
SQLSMALLINT *pcbInfoValue)
|
|
{
|
|
TRACE("SQLGetInfo");
|
|
switch (fInfoType) {
|
|
case SQL_MAX_STATEMENT_LEN:
|
|
if (rgbInfoValue)
|
|
*((SQLUINTEGER *)rgbInfoValue) = (SQLUINTEGER)65000;
|
|
if (pcbInfoValue)
|
|
*pcbInfoValue = sizeof(SQLUINTEGER);
|
|
break;
|
|
case SQL_SCHEMA_USAGE:
|
|
if (rgbInfoValue)
|
|
*((SQLSMALLINT *)rgbInfoValue) = (SQLSMALLINT)0;
|
|
if (pcbInfoValue)
|
|
*pcbInfoValue = sizeof(SQLSMALLINT);
|
|
break;
|
|
case SQL_CATALOG_NAME_SEPARATOR:
|
|
if (rgbInfoValue)
|
|
memcpy(rgbInfoValue, ".", 1);
|
|
if (pcbInfoValue)
|
|
*pcbInfoValue = 1;
|
|
break;
|
|
case SQL_CATALOG_LOCATION:
|
|
if (rgbInfoValue)
|
|
*((SQLSMALLINT *)rgbInfoValue) = (SQLSMALLINT)1;
|
|
if (pcbInfoValue)
|
|
*pcbInfoValue = sizeof(SQLSMALLINT);
|
|
break;
|
|
case SQL_IDENTIFIER_QUOTE_CHAR:
|
|
if (rgbInfoValue)
|
|
memcpy(rgbInfoValue, "\"", 1);
|
|
if (pcbInfoValue)
|
|
*pcbInfoValue = 1;
|
|
break;
|
|
case SQL_DBMS_NAME:
|
|
if (rgbInfoValue)
|
|
strncpy(rgbInfoValue, "MDBTOOLS", cbInfoValueMax);
|
|
if (pcbInfoValue)
|
|
*pcbInfoValue = 9;
|
|
break;
|
|
case SQL_DBMS_VER:
|
|
if (rgbInfoValue)
|
|
strncpy(rgbInfoValue, VERSION, cbInfoValueMax);
|
|
if (pcbInfoValue)
|
|
*pcbInfoValue = sizeof(VERSION)+1;
|
|
break;
|
|
default:
|
|
if (pcbInfoValue)
|
|
*pcbInfoValue = 0;
|
|
strcpy(sqlState, "HYC00");
|
|
return SQL_ERROR;
|
|
}
|
|
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
#ifdef ENABLE_ODBC_W
|
|
SQLRETURN SQL_API SQLGetInfoW(
|
|
SQLHDBC hdbc,
|
|
SQLUSMALLINT fInfoType,
|
|
SQLPOINTER rgbInfoValue,
|
|
SQLSMALLINT cbInfoValueMax,
|
|
SQLSMALLINT *pcbInfoValue)
|
|
{
|
|
TRACE("SQLGetInfoW");
|
|
|
|
if(fInfoType==SQL_MAX_STATEMENT_LEN||fInfoType==SQL_SCHEMA_USAGE||fInfoType==SQL_CATALOG_LOCATION)
|
|
return SQLGetInfo(hdbc,fInfoType,rgbInfoValue,cbInfoValueMax,pcbInfoValue);
|
|
|
|
SQLCHAR *tmp=calloc(cbInfoValueMax*4,1);
|
|
size_t l=cbInfoValueMax*4;
|
|
SQLRETURN ret = SQLGetInfo(hdbc, fInfoType, tmp, cbInfoValueMax*4,(SQLSMALLINT*)&l);
|
|
size_t pcb=cbInfoValueMax;
|
|
ascii2unicode((char*)tmp, &l, (char*)rgbInfoValue, &pcb);
|
|
pcb/=sizeof(SQLWCHAR);
|
|
if(pcbInfoValue)*pcbInfoValue=pcb;
|
|
free(tmp);
|
|
return ret;
|
|
}
|
|
#endif //ENABLE_ODBC_W
|
|
|
|
SQLRETURN SQL_API SQLGetStmtOption(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT fOption,
|
|
SQLPOINTER pvParam)
|
|
{
|
|
TRACE("SQLGetStmtOption");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLGetTypeInfo(
|
|
SQLHSTMT hstmt,
|
|
SQLSMALLINT fSqlType)
|
|
{
|
|
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
|
MdbTableDef *ttable;
|
|
MdbSQL *sql = stmt->sql;
|
|
MdbHandle *mdb = sql->mdb;
|
|
int row_size;
|
|
unsigned char row_buffer[MDB_PGSIZE];
|
|
unsigned int ts0, ts3, ts4, ts5, ts12;
|
|
unsigned char t0[MDB_BIND_SIZE],
|
|
t3[MDB_BIND_SIZE],
|
|
t4[MDB_BIND_SIZE],
|
|
t5[MDB_BIND_SIZE],
|
|
t12[MDB_BIND_SIZE];
|
|
int i;
|
|
MdbField fields[NUM_TYPE_INFO_COLS];
|
|
|
|
TRACE("SQLGetTypeInfo");
|
|
|
|
ttable = mdb_create_temp_table(mdb, "#typeinfo");
|
|
mdb_sql_add_temp_col(sql, ttable, 0, "TYPE_NAME", MDB_TEXT, 30, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 1, "DATA_TYPE", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 2, "COLUMN_SIZE", MDB_LONGINT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 3, "LITERAL_PREFIX", MDB_TEXT, 30, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 4, "LITERAL_SUFFIX", MDB_TEXT, 30, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 5, "CREATE_PARAMS", MDB_TEXT, 30, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 6, "NULLABLE", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 7, "CASE_SENSITIVE", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 8, "SEARCHABLE", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 9, "UNSIGNED_ATTRIBUTE", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 10, "FIXED_PREC_SCALE", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 11, "AUTO_UNIQUE_VALUE", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 12, "LOCAL_TYPE_NAME", MDB_TEXT, 30, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 13, "MINIMUM_SCALE", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 14, "MAXIMUM_SCALE", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 15, "SQL_DATA_TYPE", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 16, "SQL_DATETIME_SUB", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 17, "NUM_PREC_RADIX", MDB_INT, 0, 1);
|
|
mdb_sql_add_temp_col(sql, ttable, 18, "INTERVAL_PRECISION", MDB_INT, 0, 1);
|
|
mdb_temp_columns_end(ttable);
|
|
|
|
for (i=0; i<MAX_TYPE_INFO; i++) {
|
|
if (fSqlType && (fSqlType != type_info[i].data_type))
|
|
continue;
|
|
|
|
ts0 = mdb_ascii2unicode(mdb, (char*)type_info[i].type_name, 0, (char*)t0, MDB_BIND_SIZE);
|
|
ts3 = mdb_ascii2unicode(mdb, (char*)type_info[i].literal_prefix, 0, (char*)t3, MDB_BIND_SIZE);
|
|
ts4 = mdb_ascii2unicode(mdb, (char*)type_info[i].literal_suffix, 0, (char*)t4, MDB_BIND_SIZE);
|
|
ts5 = mdb_ascii2unicode(mdb, (char*)type_info[i].create_params, 0, (char*)t5, MDB_BIND_SIZE);
|
|
ts12 = mdb_ascii2unicode(mdb, (char*)type_info[i].local_type_name, 0, (char*)t12, MDB_BIND_SIZE);
|
|
|
|
FILL_FIELD(&fields[0], t0, ts0);
|
|
FILL_FIELD(&fields[1],&type_info[i].data_type, 0);
|
|
FILL_FIELD(&fields[2],&type_info[i].column_size, 0);
|
|
FILL_FIELD(&fields[3], t3, ts3);
|
|
FILL_FIELD(&fields[4], t4, ts4);
|
|
FILL_FIELD(&fields[5], t5, ts5);
|
|
FILL_FIELD(&fields[6],&type_info[i].nullable, 0);
|
|
FILL_FIELD(&fields[7],&type_info[i].case_sensitive, 0);
|
|
FILL_FIELD(&fields[8],&type_info[i].searchable, 0);
|
|
FILL_FIELD(&fields[9],type_info[i].unsigned_attribute, 0);
|
|
FILL_FIELD(&fields[10],&type_info[i].fixed_prec_scale, 0);
|
|
FILL_FIELD(&fields[11],&type_info[i].auto_unique_value, 0);
|
|
FILL_FIELD(&fields[12], t12, ts12);
|
|
FILL_FIELD(&fields[13],&type_info[i].minimum_scale, 0);
|
|
FILL_FIELD(&fields[14],&type_info[i].maximum_scale, 0);
|
|
FILL_FIELD(&fields[15],&type_info[i].sql_data_type, 0);
|
|
FILL_FIELD(&fields[16],type_info[i].sql_datetime_sub, 0);
|
|
FILL_FIELD(&fields[17],type_info[i].num_prec_radix, 0);
|
|
FILL_FIELD(&fields[18],type_info[i].interval_precision, 0);
|
|
|
|
row_size = mdb_pack_row(ttable, row_buffer, NUM_TYPE_INFO_COLS, fields);
|
|
mdb_add_row_to_pg(ttable,row_buffer, row_size);
|
|
ttable->num_rows++;
|
|
}
|
|
sql->cur_table = ttable;
|
|
|
|
/* return SQLExecute(hstmt); */
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLParamData(
|
|
SQLHSTMT hstmt,
|
|
SQLPOINTER *prgbValue)
|
|
{
|
|
TRACE("SQLParamData");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLPutData(
|
|
SQLHSTMT hstmt,
|
|
SQLPOINTER rgbValue,
|
|
SQLLEN cbValue)
|
|
{
|
|
TRACE("SQLPutData");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLSetConnectOption(
|
|
SQLHDBC hdbc,
|
|
SQLUSMALLINT fOption,
|
|
SQLULEN vParam)
|
|
{
|
|
TRACE("SQLSetConnectOption");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLSetStmtOption(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT fOption,
|
|
SQLULEN vParam)
|
|
{
|
|
TRACE("SQLSetStmtOption");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLSpecialColumns(
|
|
SQLHSTMT hstmt,
|
|
SQLUSMALLINT fColType,
|
|
SQLCHAR *szCatalogName,
|
|
SQLSMALLINT cbCatalogName,
|
|
SQLCHAR *szSchemaName,
|
|
SQLSMALLINT cbSchemaName,
|
|
SQLCHAR *szTableName,
|
|
SQLSMALLINT cbTableName,
|
|
SQLUSMALLINT fScope,
|
|
SQLUSMALLINT fNullable)
|
|
{
|
|
TRACE("SQLSpecialColumns");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLStatistics(
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szCatalogName,
|
|
SQLSMALLINT cbCatalogName,
|
|
SQLCHAR *szSchemaName,
|
|
SQLSMALLINT cbSchemaName,
|
|
SQLCHAR *szTableName,
|
|
SQLSMALLINT cbTableName,
|
|
SQLUSMALLINT fUnique,
|
|
SQLUSMALLINT fAccuracy)
|
|
{
|
|
TRACE("SQLStatistics");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
SQLRETURN SQL_API SQLTables( //sz* not used, so Unicode API not required.
|
|
SQLHSTMT hstmt,
|
|
SQLCHAR *szCatalogName,
|
|
SQLSMALLINT cbCatalogName,
|
|
SQLCHAR *szSchemaName,
|
|
SQLSMALLINT cbSchemaName,
|
|
SQLCHAR *szTableName,
|
|
SQLSMALLINT cbTableName,
|
|
SQLCHAR *szTableType,
|
|
SQLSMALLINT cbTableType)
|
|
{
|
|
struct _hstmt *stmt = (struct _hstmt *) hstmt;
|
|
MdbSQL *sql = stmt->sql;
|
|
MdbHandle *mdb = sql->mdb;
|
|
MdbTableDef *ttable;
|
|
MdbField fields[5];
|
|
MdbCatalogEntry *entry;
|
|
unsigned char row_buffer[MDB_PGSIZE];
|
|
char *table_types[] = {"TABLE", "SYSTEM TABLE", "VIEW"};
|
|
unsigned int i, j, row_size, ttype;
|
|
unsigned int ts2, ts3;
|
|
unsigned char t2[MDB_BIND_SIZE],
|
|
t3[MDB_BIND_SIZE];
|
|
|
|
TRACE("SQLTables");
|
|
|
|
mdb_read_catalog(mdb, MDB_ANY);
|
|
|
|
ttable = mdb_create_temp_table(mdb, "#tables");
|
|
mdb_sql_add_temp_col(sql, ttable, 0, "TABLE_CAT", MDB_TEXT, 128, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 1, "TABLE_SCHEM", MDB_TEXT, 128, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 2, "TABLE_NAME", MDB_TEXT, 128, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 3, "TABLE_TYPE", MDB_TEXT, 128, 0);
|
|
mdb_sql_add_temp_col(sql, ttable, 4, "REMARKS", MDB_TEXT, 254, 0);
|
|
mdb_temp_columns_end(ttable);
|
|
|
|
/* TODO: Sort the return list by TYPE, CAT, SCHEM, NAME */
|
|
for (i=0; i<mdb->num_catalog; i++) {
|
|
entry = g_ptr_array_index(mdb->catalog, i);
|
|
|
|
if (mdb_is_user_table(entry))
|
|
ttype = 0;
|
|
else if (mdb_is_system_table(entry))
|
|
ttype = 1;
|
|
else if (entry->object_type == MDB_QUERY)
|
|
ttype = 2;
|
|
else
|
|
continue;
|
|
|
|
/* Set all fields to NULL */
|
|
for (j=0; j<5; j++) {
|
|
FILL_FIELD(&fields[j], NULL, 0);
|
|
}
|
|
|
|
ts2 = mdb_ascii2unicode(mdb, entry->object_name, 0, (char*)t2, MDB_BIND_SIZE);
|
|
ts3 = mdb_ascii2unicode(mdb, table_types[ttype], 0, (char*)t3, MDB_BIND_SIZE);
|
|
|
|
FILL_FIELD(&fields[2], t2, ts2);
|
|
FILL_FIELD(&fields[3], t3, ts3);
|
|
|
|
row_size = mdb_pack_row(ttable, row_buffer, 5, fields);
|
|
mdb_add_row_to_pg(ttable, row_buffer, row_size);
|
|
ttable->num_rows++;
|
|
}
|
|
sql->cur_table = ttable;
|
|
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
|
|
SQLRETURN SQL_API SQLDataSources(
|
|
SQLHENV henv,
|
|
SQLUSMALLINT fDirection,
|
|
SQLCHAR *szDSN,
|
|
SQLSMALLINT cbDSNMax,
|
|
SQLSMALLINT *pcbDSN,
|
|
SQLCHAR *szDescription,
|
|
SQLSMALLINT cbDescriptionMax,
|
|
SQLSMALLINT *pcbDescription)
|
|
{
|
|
TRACE("SQLDataSources");
|
|
return SQL_SUCCESS;
|
|
}
|
|
|
|
static int _odbc_fix_literals(struct _hstmt *stmt)
|
|
{
|
|
char tmp[4096],begin_tag[11];
|
|
char *s, *d, *p;
|
|
int i, quoted = 0, find_end = 0;
|
|
char quote_char;
|
|
|
|
s=stmt->query;
|
|
d=tmp;
|
|
while (*s) {
|
|
if (!quoted && (*s=='"' || *s=='\'')) {
|
|
quoted = 1;
|
|
quote_char = *s;
|
|
} else if (quoted && *s==quote_char) {
|
|
quoted = 0;
|
|
}
|
|
if (!quoted && find_end && *s=='}') {
|
|
s++; /* ignore the end of tag */
|
|
} else if (!quoted && *s=='{') {
|
|
for (p=s,i=0;*p && *p!=' ';p++) i++;
|
|
if (i>10) {
|
|
/* garbage */
|
|
*d++=*s++;
|
|
} else {
|
|
strncpy(begin_tag, s, i);
|
|
begin_tag[i] = '\0';
|
|
/* printf("begin tag %s\n", begin_tag); */
|
|
s += i;
|
|
find_end = 1;
|
|
}
|
|
} else {
|
|
*d++=*s++;
|
|
}
|
|
}
|
|
*d='\0';
|
|
strcpy(stmt->query,tmp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _odbc_get_string_size(int size, SQLCHAR *str)
|
|
{
|
|
if (!str) {
|
|
return 0;
|
|
}
|
|
if (size==SQL_NTS) {
|
|
return strlen((char*)str);
|
|
} else {
|
|
return size;
|
|
}
|
|
return 0;
|
|
}
|
|
/*
|
|
static int _odbc_get_server_type(int clt_type)
|
|
{
|
|
switch (clt_type) {
|
|
case SQL_CHAR:
|
|
case SQL_VARCHAR:
|
|
case SQL_BIT:
|
|
case SQL_TINYINT:
|
|
case SQL_SMALLINT:
|
|
case SQL_INTEGER:
|
|
case SQL_DOUBLE:
|
|
case SQL_DECIMAL:
|
|
case SQL_NUMERIC:
|
|
case SQL_FLOAT:
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}*/
|
|
static SQLSMALLINT _odbc_get_client_type(MdbColumn *col)
|
|
{
|
|
switch (col->col_type) {
|
|
case MDB_BOOL:
|
|
return SQL_BIT;
|
|
case MDB_BYTE:
|
|
return SQL_TINYINT;
|
|
case MDB_INT:
|
|
return SQL_SMALLINT;
|
|
case MDB_LONGINT:
|
|
return SQL_INTEGER;
|
|
case MDB_MONEY:
|
|
return SQL_DECIMAL;
|
|
case MDB_FLOAT:
|
|
return SQL_FLOAT;
|
|
case MDB_DOUBLE:
|
|
return SQL_DOUBLE;
|
|
case MDB_DATETIME: ;
|
|
#if ODBCVER >= 0x0300
|
|
const char *format = mdb_col_get_prop(col, "Format");
|
|
if (format && !strcmp(format, "Short Date"))
|
|
return SQL_TYPE_DATE;
|
|
else
|
|
return SQL_TYPE_TIMESTAMP;
|
|
#endif // returns text otherwise
|
|
case MDB_TEXT:
|
|
case MDB_MEMO:
|
|
return SQL_VARCHAR;
|
|
case MDB_OLE:
|
|
return SQL_LONGVARBINARY;
|
|
default:
|
|
// fprintf(stderr,"Unknown type %d\n",srv_type);
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static const char * _odbc_get_client_type_name(MdbColumn *col)
|
|
{
|
|
switch (col->col_type) {
|
|
case MDB_BOOL:
|
|
return "BOOL";
|
|
case MDB_BYTE:
|
|
return "BYTE";
|
|
case MDB_INT:
|
|
return "INT";
|
|
case MDB_LONGINT:
|
|
return "LONGINT";
|
|
case MDB_MONEY:
|
|
return "MONEY";
|
|
case MDB_FLOAT:
|
|
return "FLOAT";
|
|
case MDB_DOUBLE:
|
|
return "DOUBLE";
|
|
case MDB_DATETIME:
|
|
return "DATETIME";
|
|
case MDB_TEXT:
|
|
return "TEXT";
|
|
case MDB_BINARY:
|
|
return "BINARY";
|
|
case MDB_MEMO:
|
|
return "MEMO";
|
|
case MDB_OLE:
|
|
return "OLE";
|
|
case MDB_REPID:
|
|
return "REPID";
|
|
case MDB_NUMERIC:
|
|
return "NUMERIC";
|
|
case MDB_COMPLEX:
|
|
return "COMPLEX";
|
|
default:
|
|
// fprintf(stderr,"Unknown type %d\n",srv_type);
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|