?? sqlite3odbc.c
字號:
/**
* @file sqlite3odbc.c
* SQLite3 ODBC Driver main module.
*
* $Id: sqlite3odbc.c,v 1.81 2008/09/13 06:22:13 chw Exp chw $
*
* Copyright (c) 2004-2008 Christian Werner <chw@ch-werner.de>
*
* See the file "license.terms" for information on usage
* and redistribution of this file and for a
* DISCLAIMER OF ALL WARRANTIES.
*/
#include "sqlite3odbc.h"
#ifndef WITHOUT_WINTERFACE
#define WINTERFACE
#endif
#ifdef WINTERFACE
#include <sqlucode.h>
#endif
#ifdef _WIN32
#include "resource3.h"
#define ODBC_INI "ODBC.INI"
#else
#define ODBC_INI ".odbc.ini"
#endif
#ifndef DRIVER_VER_INFO
#define DRIVER_VER_INFO "0.0"
#endif
#ifndef COLATTRIBUTE_LAST_ARG_TYPE
#define COLATTRIBUTE_LAST_ARG_TYPE SQLPOINTER
#endif
#undef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#undef max
#define max(a, b) ((a) < (b) ? (b) : (a))
#ifndef PTRDIFF_T
#define PTRDIFF_T int
#endif
#define array_size(x) (sizeof (x) / sizeof (x[0]))
#define stringify1(s) #s
#define stringify(s) stringify1(s)
#define verinfo(maj, min, lev) ((maj) << 16 | (min) << 8 | (lev))
/* Column types for static string column descriptions (SQLTables etc.) */
#if defined(WINTERFACE) && !defined(_WIN32)
#define SCOL_VARCHAR SQL_WVARCHAR
#define SCOL_CHAR SQL_WCHAR
#else
#define SCOL_VARCHAR SQL_VARCHAR
#define SCOL_CHAR SQL_CHAR
#endif
#define ENV_MAGIC 0x53544145
#define DBC_MAGIC 0x53544144
#define DEAD_MAGIC 0xdeadbeef
static const char *xdigits = "0123456789ABCDEFabcdef";
#ifdef MEMORY_DEBUG
static void *
xmalloc_(int n, char *file, int line)
{
int nn = n + 4 * sizeof (long);
long *p;
p = malloc(nn);
if (!p) {
#if (MEMORY_DEBUG > 1)
fprintf(stderr, "malloc\t%d\tNULL\t%s:%d\n", n, file, line);
#endif
return NULL;
}
p[0] = 0xdead1234;
nn = nn / sizeof (long) - 1;
p[1] = n;
p[nn] = 0xdead5678;
#if (MEMORY_DEBUG > 1)
fprintf(stderr, "malloc\t%d\t%p\t%s:%d\n", n, &p[2], file, line);
#endif
return (void *) &p[2];
}
static void *
xrealloc_(void *old, int n, char *file, int line)
{
int nn = n + 4 * sizeof (long), nnn;
long *p, *pp;
if (n == 0 || !old) {
return xmalloc_(n, file, line);
}
p = &((long *) old)[-2];
if (p[0] != 0xdead1234) {
fprintf(stderr, "*** low end corruption @ %p\n", old);
abort();
}
nnn = p[1] + 4 * sizeof (long);
nnn = nnn / sizeof (long) - 1;
if (p[nnn] != 0xdead5678) {
fprintf(stderr, "*** high end corruption @ %p\n", old);
abort();
}
pp = realloc(p, nn);
if (!pp) {
#if (MEMORY_DEBUG > 1)
fprintf(stderr, "realloc\t%p,%d\tNULL\t%s:%d\n", old, n, file, line);
#endif
return NULL;
}
#if (MEMORY_DEBUG > 1)
fprintf(stderr, "realloc\t%p,%d\t%p\t%s:%d\n", old, n, &pp[2], file, line);
#endif
p = pp;
p[1] = n;
nn = nn / sizeof (long) - 1;
p[nn] = 0xdead5678;
return (void *) &p[2];
}
static void
xfree_(void *x, char *file, int line)
{
long *p;
int n;
if (!x) {
return;
}
p = &((long *) x)[-2];
if (p[0] != 0xdead1234) {
fprintf(stderr, "*** low end corruption @ %p\n", x);
abort();
}
n = p[1] + 4 * sizeof (long);
n = n / sizeof (long) - 1;
if (p[n] != 0xdead5678) {
fprintf(stderr, "*** high end corruption @ %p\n", x);
abort();
}
#if (MEMORY_DEBUG > 1)
fprintf(stderr, "free\t%p\t\t%s:%d\n", x, file, line);
#endif
free(p);
}
static void
xfree__(void *x)
{
xfree_(x, "unknown location", 0);
}
static char *
xstrdup_(const char *str, char *file, int line)
{
char *p;
if (!str) {
#if (MEMORY_DEBUG > 1)
fprintf(stderr, "strdup\tNULL\tNULL\t%s:%d\n", file, line);
#endif
return NULL;
}
p = xmalloc_(strlen(str) + 1, file, line);
if (p) {
strcpy(p, str);
}
#if (MEMORY_DEBUG > 1)
fprintf(stderr, "strdup\t%p\t%p\t%s:%d\n", str, p, file, line);
#endif
return p;
}
#define xmalloc(x) xmalloc_(x, __FILE__, __LINE__)
#define xrealloc(x,y) xrealloc_(x, y, __FILE__, __LINE__)
#define xfree(x) xfree_(x, __FILE__, __LINE__)
#define xstrdup(x) xstrdup_(x, __FILE__, __LINE__)
#else
#define xmalloc(x) malloc(x)
#define xrealloc(x,y) realloc(x, y)
#define xfree(x) free(x)
#define xstrdup(x) strdup_(x)
#endif
#ifdef _WIN32
#define vsnprintf _vsnprintf
#define snprintf _snprintf
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
static HINSTANCE NEAR hModule; /* Saved module handle for resources */
#endif
#ifdef _WIN32
/*
* SQLHENV, SQLHDBC, and SQLHSTMT synchronization
* is done using a critical section in ENV structure.
*/
#define HDBC_LOCK(hdbc) \
{ \
DBC *d; \
\
if ((hdbc) == SQL_NULL_HDBC) { \
return SQL_INVALID_HANDLE; \
} \
d = (DBC *) (hdbc); \
if (d->magic != DBC_MAGIC || !d->env) { \
return SQL_INVALID_HANDLE; \
} \
if (d->env->magic != ENV_MAGIC) { \
return SQL_INVALID_HANDLE; \
} \
EnterCriticalSection(&d->env->cs); \
d->env->owner = GetCurrentThreadId(); \
}
#define HDBC_UNLOCK(hdbc) \
if ((hdbc) != SQL_NULL_HDBC) { \
DBC *d; \
\
d = (DBC *) (hdbc); \
if (d->magic == DBC_MAGIC && d->env && \
d->env->magic == ENV_MAGIC) { \
d->env->owner = 0; \
LeaveCriticalSection(&d->env->cs); \
} \
}
#define HSTMT_LOCK(hstmt) \
{ \
DBC *d; \
\
if ((hstmt) == SQL_NULL_HSTMT) { \
return SQL_INVALID_HANDLE; \
} \
d = (DBC *) ((STMT *) (hstmt))->dbc; \
if (d->magic != DBC_MAGIC || !d->env) { \
return SQL_INVALID_HANDLE; \
} \
if (d->env->magic != ENV_MAGIC) { \
return SQL_INVALID_HANDLE; \
} \
EnterCriticalSection(&d->env->cs); \
d->env->owner = GetCurrentThreadId(); \
}
#define HSTMT_UNLOCK(hstmt) \
if ((hstmt) != SQL_NULL_HSTMT) { \
DBC *d; \
\
d = (DBC *) ((STMT *) (hstmt))->dbc; \
if (d->magic == DBC_MAGIC && d->env && \
d->env->magic == ENV_MAGIC) { \
d->env->owner = 0; \
LeaveCriticalSection(&d->env->cs); \
} \
}
#else
/*
* On UN*X assume that we are single-threaded or
* the driver manager provides serialization for us.
*
* In iODBC (3.52.x) serialization can be turned
* on using the DSN property "ThreadManager=yes".
*
* In unixODBC that property is named
* "Threading=0-3" and takes one of these values:
*
* 0 - no protection
* 1 - statement level protection
* 2 - connection level protection
* 3 - environment level protection
*
* unixODBC 2.2.11 uses environment level protection
* by default when it has been built with pthread
* support.
*/
#define HDBC_LOCK(hdbc)
#define HDBC_UNLOCK(hdbc)
#define HSTMT_LOCK(hdbc)
#define HSTMT_UNLOCK(hdbc)
#endif
#if defined(ENABLE_NVFS) && ENABLE_NVFS
extern void nvfs_init(void);
extern const char *nvfs_makevfs(const char *);
#endif
/*
* tolower() replacement w/o locale
*/
static const char upper_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const char lower_chars[] = "abcdefghijklmnopqrstuvwxyz";
static int
TOLOWER(int c)
{
if (c) {
char *p = strchr(upper_chars, c);
if (p) {
c = lower_chars[p - upper_chars];
}
}
return c;
}
/*
* isdigit() replacement w/o ctype.h
*/
static const char digit_chars[] = "0123456789";
#define ISDIGIT(c) \
((c) && strchr(digit_chars, (c)) != NULL)
/*
* isspace() replacement w/o ctype.h
*/
static const char space_chars[] = " \f\n\r\t\v";
#define ISSPACE(c) \
((c) && strchr(space_chars, (c)) != NULL)
/*
* Forward declarations of static functions.
*/
static void dbtraceapi(DBC *d, char *fn, const char *sql);
static void freedyncols(STMT *s);
static void freeresult(STMT *s, int clrcols);
static void freerows(char **rowp);
static void unbindcols(STMT *s);
static SQLRETURN drvexecute(SQLHSTMT stmt, int initial);
static SQLRETURN freestmt(HSTMT stmt);
static SQLRETURN mkbindcols(STMT *s, int ncols);
static SQLRETURN setupdyncols(STMT *s, sqlite3_stmt *s3stmt, int *ncolsp);
static SQLRETURN setupparbuf(STMT *s, BINDPARM *p);
static SQLRETURN starttran(STMT *s);
static SQLRETURN setupparam(STMT *s, char *sql, int pnum);
#if defined(_WIN32) && defined(WINTERFACE)
/* MS Access hack part 1 (reserved error -7748) */
static COL statSpec[13];
#endif
#if (MEMORY_DEBUG < 1)
/**
* Duplicate string using xmalloc().
* @param str string to be duplicated
* @result pointer to new string or NULL
*/
static char *
strdup_(const char *str)
{
char *p = NULL;
if (str) {
p = xmalloc(strlen(str) + 1);
if (p) {
strcpy(p, str);
}
}
return p;
}
#endif
#ifdef WINTERFACE
/**
* Return length of UNICODE string.
* @param str UNICODE string
* @result length of string
*/
static int
uc_strlen(SQLWCHAR *str)
{
int len = 0;
if (str) {
while (*str) {
++len;
++str;
}
}
return len;
}
/**
* Copy UNICODE string like strncpy().
* @param dest destination area
* @param src source area
* @param len length of source area
* @return pointer to destination area
*/
static SQLWCHAR *
uc_strncpy(SQLWCHAR *dest, SQLWCHAR *src, int len)
{
int i = 0;
while (i < len) {
if (!src[i]) {
break;
}
dest[i] = src[i];
++i;
}
if (i < len) {
dest[i] = 0;
}
return dest;
}
/**
* Make UNICODE string from UTF8 string into buffer.
* @param str UTF8 string to be converted
* @param uc destination area to receive UNICODE string
* @param ucLen byte length of destination area
*/
static void
uc_from_utf_buf(unsigned char *str, SQLWCHAR *uc, int ucLen)
{
ucLen = ucLen / sizeof (SQLWCHAR);
if (!uc || ucLen < 0) {
return;
}
uc[0] = 0;
if (str) {
int i = 0;
while (*str && i < ucLen) {
unsigned char c = str[0];
if (c < 0xc0) {
uc[i++] = c;
++str;
} else if (c < 0xe0) {
if ((str[1] & 0xc0) == 0x80) {
unsigned long t = ((c & 0x1f) << 6) | (str[1] & 0x3f);
uc[i++] = t;
str += 2;
} else {
uc[i++] = c;
++str;
}
} else if (c < 0xf0) {
if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80) {
unsigned long t = ((c & 0x0f) << 12) |
((str[1] & 0x3f) << 6) | (str[2] & 0x3f);
uc[i++] = t;
str += 3;
} else {
uc[i++] = c;
++str;
}
} else if (c < 0xf8) {
if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 &&
(str[3] & 0xc0) == 0x80) {
unsigned long t = ((c & 0x03) << 18) |
((str[1] & 0x3f) << 12) | ((str[2] & 0x3f) << 6) |
(str[4] & 0x3f);
if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
t >= 0x10000) {
t -= 0x10000;
uc[i++] = 0xd800 | (t & 0x3ff);
if (i >= ucLen) {
break;
}
t = 0xdc00 | ((t >> 10) & 0x3ff);
}
uc[i++] = t;
str += 4;
} else {
uc[i++] = c;
++str;
}
} else if (c < 0xfc) {
if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 &&
(str[3] & 0xc0) == 0x80 && (str[4] & 0xc0) == 0x80) {
unsigned long t = ((c & 0x01) << 24) |
((str[1] & 0x3f) << 18) | ((str[2] & 0x3f) << 12) |
((str[4] & 0x3f) << 6) | (str[5] & 0x3f);
if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
t >= 0x10000) {
t -= 0x10000;
uc[i++] = 0xd800 | (t & 0x3ff);
if (i >= ucLen) {
break;
}
t = 0xdc00 | ((t >> 10) & 0x3ff);
}
uc[i++] = t;
str += 5;
} else {
uc[i++] = c;
++str;
}
} else {
/* ignore */
++str;
}
}
if (i < ucLen) {
uc[i] = 0;
}
}
}
/**
* Make UNICODE string from UTF8 string.
* @param str UTF8 string to be converted
* @param len length of UTF8 string
* @return alloc'ed UNICODE string to be free'd by uc_free()
*/
static SQLWCHAR *
uc_from_utf(unsigned char *str, int len)
{
SQLWCHAR *uc = NULL;
if (str) {
if (len == SQL_NTS) {
len = strlen((char *) str);
}
len = sizeof (SQLWCHAR) * (len + 1);
uc = xmalloc(len);
if (uc) {
uc_from_utf_buf(str, uc, len);
}
}
return uc;
}
/**
* Make UTF8 string from UNICODE string.
* @param str UNICODE string to be converted
* @param len length of UNICODE string in bytes
* @return alloc'ed UTF8 string to be free'd by uc_free()
*/
static char *
uc_to_utf(SQLWCHAR *str, int len)
{
int i;
char *cp, *ret = NULL;
if (!str) {
return ret;
}
if (len == SQL_NTS) {
len = uc_strlen(str);
} else {
len = len / sizeof (SQLWCHAR);
}
cp = xmalloc(len * 6 + 1);
if (!cp) {
return ret;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -