📄 sqlite3odbc.c
字号:
ret = cp;
for (i = 0; i < len; i++) {
unsigned long c = str[i];
if (sizeof (SQLWCHAR) == 2 * sizeof (char)) {
c &= 0xffff;
}
if (c < 0xc0) {
*cp++ = c;
} else if (c < 0x800) {
*cp++ = 0xc0 | ((c >> 6) & 0x1f);
*cp++ = 0x80 | (c & 0x3f);
} else if (c < 0x10000) {
if (sizeof (SQLWCHAR) == 2 * sizeof (char) &&
c >= 0xd800 && c <= 0xdbff && i + 1 < len) {
unsigned long c2 = str[i + 1] & 0xffff;
if (c2 >= 0xdc00 && c <= 0xdfff) {
c = ((c & 0x3ff) | ((c2 & 0x3ff) << 10)) + 0x10000;
*cp++ = 0xf0 | ((c >> 18) & 0x07);
*cp++ = 0x80 | ((c >> 12) & 0x3f);
*cp++ = 0x80 | ((c >> 6) & 0x3f);
*cp++ = 0x80 | (c & 0x3f);
++i;
continue;
}
}
*cp++ = 0xe0 | ((c >> 12) & 0x0f);
*cp++ = 0x80 | ((c >> 6) & 0x3f);
*cp++ = 0x80 | (c & 0x3f);
} else if (c < 0x200000) {
*cp++ = 0xf0 | ((c >> 18) & 0x07);
*cp++ = 0x80 | ((c >> 12) & 0x3f);
*cp++ = 0x80 | ((c >> 6) & 0x3f);
*cp++ = 0x80 | (c & 0x3f);
} else if (c < 0x4000000) {
*cp++ = 0xf8 | ((c >> 24) & 0x03);
*cp++ = 0x80 | ((c >> 18) & 0x3f);
*cp++ = 0x80 | ((c >> 12) & 0x3f);
*cp++ = 0x80 | ((c >> 6) & 0x3f);
*cp++ = 0x80 | (c & 0x3f);
} else if (c < 0x80000000) {
*cp++ = 0xfc | ((c >> 31) & 0x01);
*cp++ = 0x80 | ((c >> 24) & 0x3f);
*cp++ = 0x80 | ((c >> 18) & 0x3f);
*cp++ = 0x80 | ((c >> 12) & 0x3f);
*cp++ = 0x80 | ((c >> 6) & 0x3f);
*cp++ = 0x80 | (c & 0x3f);
}
}
*cp = '\0';
return ret;
}
/**
* Make UTF8 string from UNICODE string.
* @param str UNICODE string to be converted
* @param len length of UNICODE string in characters
* @return alloc'ed UTF8 string to be free'd by uc_free()
*/
static char *
uc_to_utf_c(SQLWCHAR *str, int len)
{
if (len != SQL_NTS) {
len = len * sizeof (SQLWCHAR);
}
return uc_to_utf(str, len);
}
#endif /* WINTERFACE */
#if defined(WINTERFACE) || defined(_WIN32)
/**
* Free converted UTF8 or UNICODE string.
* @param str string to be free'd
*/
static void
uc_free(void *str)
{
if (str) {
xfree(str);
}
}
#endif
#ifdef _WIN32
/**
* Convert multibyte, current code page string to UTF8 string,
* @param str multibyte string to be converted
* @param len length of multibyte string
* @return alloc'ed UTF8 string to be free'd by uc_free()
*/
static char *
wmb_to_utf(char *str, int len)
{
WCHAR *wstr;
OSVERSIONINFO ovi;
int nchar, is2k, cp = CP_OEMCP;
ovi.dwOSVersionInfoSize = sizeof (ovi);
GetVersionEx(&ovi);
is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
if (AreFileApisANSI()) {
cp = is2k ? CP_THREAD_ACP : CP_ACP;
}
nchar = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
if (!wstr) {
return NULL;
}
wstr[0] = 0;
nchar = MultiByteToWideChar(cp, 0, str, len, wstr, nchar);
wstr[nchar] = 0;
str = xmalloc((nchar + 1) * 7);
if (!str) {
xfree(wstr);
return NULL;
}
str[0] = '\0';
nchar = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, nchar * 7, 0, 0);
str[nchar] = '\0';
xfree(wstr);
return str;
}
/**
* Convert UTF8 string to multibyte, current code page string,
* @param str UTF8 string to be converted
* @param len length of UTF8 string
* @return alloc'ed multibyte string to be free'd by uc_free()
*/
static char *
utf_to_wmb(char *str, int len)
{
WCHAR *wstr;
OSVERSIONINFO ovi;
int nchar, is2k, cp = CP_OEMCP;
ovi.dwOSVersionInfoSize = sizeof (ovi);
GetVersionEx(&ovi);
is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
if (AreFileApisANSI()) {
cp = is2k ? CP_THREAD_ACP : CP_ACP;
}
nchar = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
if (!wstr) {
return NULL;
}
wstr[0] = 0;
nchar = MultiByteToWideChar(CP_UTF8, 0, str, len, wstr, nchar);
wstr[nchar] = 0;
str = xmalloc((nchar + 1) * 7);
if (!str) {
xfree(wstr);
return NULL;
}
str[0] = '\0';
nchar = WideCharToMultiByte(cp, 0, wstr, -1, str, nchar * 7, 0, 0);
str[nchar] = '\0';
xfree(wstr);
return str;
}
#ifdef WINTERFACE
/**
* Convert multibyte, current code page string to UNICODE string,
* @param str multibyte string to be converted
* @param len length of multibyte string
* @return alloc'ed UNICODE string to be free'd by uc_free()
*/
static WCHAR *
wmb_to_uc(char *str, int len)
{
WCHAR *wstr;
OSVERSIONINFO ovi;
int nchar, is2k, cp = CP_OEMCP;
ovi.dwOSVersionInfoSize = sizeof (ovi);
GetVersionEx(&ovi);
is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
if (AreFileApisANSI()) {
cp = is2k ? CP_THREAD_ACP : CP_ACP;
}
nchar = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
wstr = xmalloc((nchar + 1) * sizeof (WCHAR));
if (!wstr) {
return NULL;
}
wstr[0] = 0;
nchar = MultiByteToWideChar(cp, 0, str, len, wstr, nchar);
wstr[nchar] = 0;
return wstr;
}
/**
* Convert UNICODE string to multibyte, current code page string,
* @param str UNICODE string to be converted
* @param len length of UNICODE string
* @return alloc'ed multibyte string to be free'd by uc_free()
*/
static char *
uc_to_wmb(WCHAR *wstr, int len)
{
char *str;
OSVERSIONINFO ovi;
int nchar, is2k, cp = CP_OEMCP;
ovi.dwOSVersionInfoSize = sizeof (ovi);
GetVersionEx(&ovi);
is2k = ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4;
if (AreFileApisANSI()) {
cp = is2k ? CP_THREAD_ACP : CP_ACP;
}
nchar = WideCharToMultiByte(cp, 0, wstr, len, NULL, 0, 0, 0);
str = xmalloc((nchar + 1) * 2);
if (!str) {
return NULL;
}
str[0] = '\0';
nchar = WideCharToMultiByte(cp, 0, wstr, len, str, nchar * 2, 0, 0);
str[nchar] = '\0';
return str;
}
#endif /* WINTERFACE */
#endif /* _WIN32 */
#ifdef USE_DLOPEN_FOR_GPPS
#include <dlfcn.h>
#define SQLGetPrivateProfileString(A,B,C,D,E,F) drvgpps(d,A,B,C,D,E,F)
/*
* EXPERIMENTAL: SQLGetPrivateProfileString infrastructure using
* dlopen(), in theory this makes the driver independent from the
* driver manager, i.e. the same driver binary can run with iODBC
* and unixODBC.
*/
static void
drvgetgpps(DBC *d)
{
void *lib;
int (*gpps)();
lib = dlopen("libodbcinst.so.1", RTLD_LAZY);
if (!lib) {
lib = dlopen("libodbcinst.so", RTLD_LAZY);
}
if (!lib) {
lib = dlopen("libiodbcinst.so.2", RTLD_LAZY);
}
if (!lib) {
lib = dlopen("libiodbcinst.so", RTLD_LAZY);
}
if (lib) {
gpps = (int (*)()) dlsym(lib, "SQLGetPrivateProfileString");
if (!gpps) {
dlclose(lib);
return;
}
d->instlib = lib;
d->gpps = gpps;
}
}
static void
drvrelgpps(DBC *d)
{
if (d->instlib) {
dlclose(d->instlib);
d->instlib = 0;
}
}
static int
drvgpps(DBC *d, char *sect, char *ent, char *def, char *buf,
int bufsiz, char *fname)
{
if (d->gpps) {
return d->gpps(sect, ent, def, buf, bufsiz, fname);
}
strncpy(buf, def, bufsiz);
buf[bufsiz - 1] = '\0';
return 1;
}
#else
#include <odbcinst.h>
#define drvgetgpps(d)
#define drvrelgpps(d)
#endif
/*
* Internal function to bind SQLite3 parameters.
*/
static void
s3bind(sqlite3_stmt *stmt, int nparams, BINDPARM *p)
{
int i;
if (stmt && p && nparams > 0) {
for (i = 0; i < nparams; i++, p++) {
switch (p->s3type) {
default:
case SQLITE_NULL:
sqlite3_bind_null(stmt, i + 1);
break;
case SQLITE_TEXT:
sqlite3_bind_text(stmt, i + 1, p->s3val, p->s3size,
SQLITE_STATIC);
break;
case SQLITE_BLOB:
sqlite3_bind_blob(stmt, i + 1, p->s3val, p->s3size,
SQLITE_STATIC);
break;
case SQLITE_FLOAT:
sqlite3_bind_double(stmt, i + 1, p->s3dval);
break;
case SQLITE_INTEGER:
if (p->s3size > sizeof (int)) {
sqlite3_bind_int64(stmt, i + 1, p->s3lival);
} else {
sqlite3_bind_int(stmt, i + 1, p->s3ival);
}
break;
}
}
}
}
/*
* Internal structure for managing driver's
* sqlite3_get_table() implementation.
*/
typedef struct tblres {
char **resarr;
char *errmsg;
sqlite3_stmt *stmt;
STMT *s;
int nres;
int nalloc;
int nrow;
int ncol;
PTRDIFF_T ndata;
int rc;
} TBLRES;
/*
* Driver's version of sqlite3_get_table() and friends which are
* capable of dealing with blobs.
*/
static int
drvgettable_row(TBLRES *t, int ncol, int rc)
{
int need;
int i;
char *p;
if (t->nrow == 0 && rc == SQLITE_ROW) {
need = ncol * 2;
} else {
need = ncol;
}
if (t->ndata + need >= t->nalloc) {
char **resnew;
int nalloc = t->nalloc * 2 + need + 1;
resnew = xrealloc(t->resarr, sizeof (char *) * nalloc);
if (!resnew) {
nomem:
t->rc = SQLITE_NOMEM;
return 1;
}
t->nalloc = nalloc;
t->resarr = resnew;
}
/* column names when first row */
if (t->nrow == 0) {
t->ncol = ncol;
for (i = 0; i < ncol; i++) {
p = (char *) sqlite3_column_name(t->stmt, i);
if (p) {
char *q = xmalloc(strlen(p) + 1);
if (!q) {
goto nomem;
}
strcpy(q, p);
p = q;
}
t->resarr[t->ndata++] = p;
}
if (t->s && t->s->guessed_types) {
int ncol2 = ncol;
setupdyncols(t->s, t->stmt, &ncol2);
t->s->guessed_types = 0;
t->s->ncols = ncol;
}
} else if (t->ncol != ncol) {
t->errmsg = sqlite3_mprintf("drvgettable() called with two or"
" more incompatible queries");
t->rc = SQLITE_ERROR;
return 1;
}
/* copy row data */
if (rc == SQLITE_ROW) {
for (i = 0; i < ncol; i++) {
int coltype = sqlite3_column_type(t->stmt, i);
p = NULL;
if (coltype == SQLITE_BLOB) {
int k, nbytes = sqlite3_column_bytes(t->stmt, i);
char *qp;
unsigned const char *bp;
bp = sqlite3_column_blob(t->stmt, i);
qp = xmalloc(nbytes * 2 + 4);
if (!qp) {
goto nomem;
}
p = qp;
*qp++ = 'X';
*qp++ = '\'';
for (k = 0; k < nbytes; k++) {
*qp++ = xdigits[(bp[k] >> 4)];
*qp++ = xdigits[(bp[k] & 0xF)];
}
*qp++ = '\'';
*qp = '\0';
} else if (coltype != SQLITE_NULL) {
p = xstrdup((char *) sqlite3_column_text(t->stmt, i));
if (!p) {
goto nomem;
}
}
t->resarr[t->ndata++] = p;
}
t->nrow++;
}
return 0;
}
static int
drvgettable(STMT *s, const char *sql, char ***resp, int *nrowp,
int *ncolp, char **errp, int nparam, BINDPARM *p)
{
DBC *d = (DBC *) s->dbc;
int rc = SQLITE_OK;
TBLRES tres;
const char *sqlleft;
int nretry = 0, haveerr = 0;
if (!resp) {
return SQLITE_ERROR;
}
*resp = NULL;
if (nrowp) {
*nrowp = 0;
}
if (ncolp) {
*ncolp = 0;
}
if (!sql) {
return SQLITE_OK;
}
tres.errmsg = NULL;
tres.nres = 0;
tres.nrow = 0;
tres.ncol = 0;
tres.ndata = 1;
tres.nalloc = 20;
tres.rc = SQLITE_OK;
tres.resarr = xmalloc(sizeof (char *) * tres.nalloc);
tres.stmt = NULL;
tres.s = s;
if (!tres.resarr) {
return SQLITE_NOMEM;
}
tres.resarr[0] = 0;
while (*sql && (rc == SQLITE_OK ||
(rc == SQLITE_SCHEMA && (++nretry) < 2))) {
int ncol;
tres.stmt = NULL;
#if defined(HAVE_SQLITE3PREPAREV2) && HAVE_SQLITE3PREPAREV2
dbtraceapi(d, "sqlite3_prepare_v2", sql);
rc = sqlite3_prepare_v2(d->sqlite, sql, -1, &tres.stmt, &sqlleft);
#else
dbtraceapi(d, "sqlite3_prepare", sql);
rc = sqlite3_prepare(d->sqlite, sql, -1, &tres.stmt, &sqlleft);
#endif
if (rc != SQLITE_OK) {
if (tres.stmt) {
dbtraceapi(d, "sqlite3_finalize", 0);
sqlite3_finalize(tres.stmt);
tres.stmt = NULL;
}
continue;
}
if (!tres.stmt) {
/* this happens for a comment or white-space */
sql = sqlleft;
continue;
}
if (sqlite3_bind_parameter_count(tres.stmt) != nparam) {
if (errp) {
*errp =
sqlite3_mprintf("%s", "parameter marker count incorrect");
}
haveerr = 1;
rc = SQLITE_ERROR;
goto tbldone;
}
s3bind(tres.stmt, nparam, p);
ncol = sqlite3_column_count(tres.stmt);
while (1) {
rc = sqlite3_step(tres.stmt);
if (rc == SQLITE_ROW || rc == SQLITE_DONE) {
if (drvgettable_row(&tres, ncol, rc)) {
rc = SQLITE_ABORT;
goto tbldone;
}
}
if (rc != SQLITE_ROW) {
dbtraceapi(d, "sqlite3_finalize", 0);
rc = sqlite3_finalize(tres.stmt);
tres.stmt = 0;
if (rc != SQLITE_SCHEMA) {
nretry = 0;
sql = sqlleft;
while (ISSPACE(*sql)) {
sql++;
}
}
if (rc == SQLITE_DONE) {
rc = SQLITE_OK;
}
break;
}
}
}
tbldone:
if (tres.stmt) {
dbtraceapi(d, "sqlite3_finalize", 0);
sqlite3_finalize(tres.stmt);
}
if (haveerr) {
/* message already in *errp if any */
} else if (rc != SQLITE_OK && rc == sqlite3_errcode(d->sqlite) && errp) {
*errp = sqlite3_mprintf("%s", sqlite3_errmsg(d->sqlite));
} else if (errp) {
*errp = NULL;
}
if (tres.resarr) {
tres.resarr[0] = (char *) (tres.ndata - 1);
}
if (rc == SQLITE_ABORT) {
freerows(&tres.resarr[1]);
if (tres.errmsg) {
if (errp) {
if (*errp) {
sqlite3_free(*errp);
}
*errp = tres.errmsg;
} else {
sqlite3_free(tres.errmsg);
}
}
return tres.rc;
}
sqlite3_free(tres.errmsg);
if (rc != SQLITE_OK) {
freerows(&tres.resarr[1]);
return rc;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -