?? sqlite3odbc.c
字號(hào):
*resp = &tres.resarr[1];
if (ncolp) {
*ncolp = tres.ncol;
}
if (nrowp) {
*nrowp = tres.nrow;
}
return rc;
}
/**
* Set error message and SQL state on DBC
* @param d database connection pointer
* @param naterr native error code
* @param msg error message
* @param st SQL state
*/
#if defined(__GNUC__) && (__GNUC__ >= 2)
static void setstatd(DBC *, int, char *, char *, ...)
__attribute__((format (printf, 3, 5)));
#endif
static void
setstatd(DBC *d, int naterr, char *msg, char *st, ...)
{
va_list ap;
if (!d) {
return;
}
d->naterr = naterr;
d->logmsg[0] = '\0';
if (msg) {
int count;
va_start(ap, st);
count = vsnprintf((char *) d->logmsg, sizeof (d->logmsg), msg, ap);
va_end(ap);
if (count < 0) {
d->logmsg[sizeof (d->logmsg) - 1] = '\0';
}
}
if (!st) {
st = "?????";
}
strncpy(d->sqlstate, st, 5);
d->sqlstate[5] = '\0';
}
/**
* Set error message and SQL state on statement
* @param s statement pointer
* @param naterr native error code
* @param msg error message
* @param st SQL state
*/
#if defined(__GNUC__) && (__GNUC__ >= 2)
static void setstat(STMT *, int, char *, char *, ...)
__attribute__((format (printf, 3, 5)));
#endif
static void
setstat(STMT *s, int naterr, char *msg, char *st, ...)
{
va_list ap;
if (!s) {
return;
}
s->naterr = naterr;
s->logmsg[0] = '\0';
if (msg) {
int count;
va_start(ap, st);
count = vsnprintf((char *) s->logmsg, sizeof (s->logmsg), msg, ap);
va_end(ap);
if (count < 0) {
s->logmsg[sizeof (s->logmsg) - 1] = '\0';
}
}
if (!st) {
st = "?????";
}
strncpy(s->sqlstate, st, 5);
s->sqlstate[5] = '\0';
}
/**
* Report IM001 (not implemented) SQL error code for HDBC.
* @param dbc database connection handle
* @result ODBC error code
*/
static SQLRETURN
drvunimpldbc(HDBC dbc)
{
DBC *d;
if (dbc == SQL_NULL_HDBC) {
return SQL_INVALID_HANDLE;
}
d = (DBC *) dbc;
setstatd(d, -1, "not supported", "IM001");
return SQL_ERROR;
}
/**
* Report IM001 (not implemented) SQL error code for HSTMT.
* @param stmt statement handle
* @result ODBC error code
*/
static SQLRETURN
drvunimplstmt(HSTMT stmt)
{
STMT *s;
if (stmt == SQL_NULL_HSTMT) {
return SQL_INVALID_HANDLE;
}
s = (STMT *) stmt;
setstat(s, -1, "not supported", "IM001");
return SQL_ERROR;
}
/**
* Free memory given pointer to memory pointer.
* @param x pointer to pointer to memory to be free'd
*/
static void
freep(void *x)
{
if (x && ((char **) x)[0]) {
xfree(((char **) x)[0]);
((char **) x)[0] = NULL;
}
}
/**
* Report S1000 (out of memory) SQL error given STMT.
* @param s statement pointer
* @result ODBC error code
*/
static SQLRETURN
nomem(STMT *s)
{
setstat(s, -1, "out of memory", (*s->ov3) ? "HY000" : "S1000");
return SQL_ERROR;
}
/**
* Report S1000 (not connected) SQL error given STMT.
* @param s statement pointer
* @result ODBC error code
*/
static SQLRETURN
noconn(STMT *s)
{
setstat(s, -1, "not connected", (*s->ov3) ? "HY000" : "S1000");
return SQL_ERROR;
}
/**
* Internal locale neutral strtod function.
* @param data pointer to string
* @param endp pointer for ending character
* @result double value
*/
static double
ln_strtod(const char *data, char **endp)
{
#if defined(HAVE_LOCALECONV) || defined(_WIN32)
struct lconv *lc;
char buf[128], *p, *end;
double value;
lc = localeconv();
if (lc && lc->decimal_point && lc->decimal_point[0] &&
lc->decimal_point[0] != '.') {
strncpy(buf, data, sizeof (buf) - 1);
buf[sizeof (buf) - 1] = '\0';
p = strchr(buf, '.');
if (p) {
*p = lc->decimal_point[0];
}
p = buf;
} else {
p = (char *) data;
}
value = strtod(p, &end);
end = (char *) data + (end - p);
if (endp) {
*endp = end;
}
return value;
#else
return strtod(data, endp);
#endif
}
/**
* Strip quotes from quoted string in-place.
* @param str string
*/
static char *
unquote(char *str)
{
if (str) {
int len = strlen(str);
if (len > 1) {
if ((str[0] == '\'' && str[len - 1] == '\'') ||
(str[0] == '"' && str[len - 1] == '"') ||
(str[0] == '[' && str[len - 1] == ']')) {
str[len - 1] = '\0';
strcpy(str, str + 1);
}
}
}
return str;
}
/**
* Unescape search pattern for e.g. table name in
* catalog functions. Replacements in string are done in-place.
* @param str string
* @result number of pattern characters in string or 0
*/
static int
unescpat(char *str)
{
char *p, *q;
int count = 0;
p = str;
while ((q = strchr(p, '_')) != NULL) {
if (q == str || q[-1] != '\\') {
count++;
}
p = q + 1;
}
p = str;
while ((q = strchr(p, '%')) != NULL) {
if (q == str || q[-1] != '\\') {
count++;
}
p = q + 1;
}
p = str;
while ((q = strchr(p, '\\')) != NULL) {
if (q[1] == '\\' || q[1] == '_' || q[1] == '%') {
strcpy(q, q + 1);
}
p = q + 1;
}
return count;
}
/**
* SQL LIKE string match with optional backslash escape handling.
* @param str string
* @param pat pattern
* @param esc when true, treat literally "\\" as "\", "\?" as "?", "\_" as "_"
* @result true when pattern matched
*/
static int
namematch(char *str, char *pat, int esc)
{
int cp, ch;
while (1) {
cp = TOLOWER(*pat);
if (cp == '\0') {
if (*str != '\0') {
goto nomatch;
}
break;
}
if (*str == '\0' && cp != '%') {
goto nomatch;
}
if (cp == '%') {
while (*pat == '%') {
++pat;
}
cp = TOLOWER(*pat);
if (cp == '\0') {
break;
}
while (1) {
if (cp != '_' && cp != '\\') {
while (*str) {
ch = TOLOWER(*str);
if (ch == cp) {
break;
}
++str;
}
}
if (namematch(str, pat, esc)) {
goto match;
}
if (*str == '\0') {
goto nomatch;
}
ch = TOLOWER(*str);
++str;
}
}
if (cp == '_') {
pat++;
str++;
continue;
}
if (esc && cp == '\\' &&
(pat[1] == '\\' || pat[1] == '%' || pat[1] == '_')) {
++pat;
cp = TOLOWER(*pat);
}
ch = TOLOWER(*str++);
++pat;
if (ch != cp) {
goto nomatch;
}
}
match:
return 1;
nomatch:
return 0;
}
/**
* Busy callback for SQLite.
* @param udata user data, pointer to DBC
* @param count count of subsequenct calls
* @result true or false
*/
static int
busy_handler(void *udata, int count)
{
DBC *d = (DBC *) udata;
long t1;
int ret = 0;
#ifndef _WIN32
struct timeval tv;
#endif
if (d->busyint) {
d->busyint = 0;
return ret;
}
if (d->timeout <= 0) {
return ret;
}
if (count <= 1) {
#ifdef _WIN32
d->t0 = GetTickCount();
#else
gettimeofday(&tv, NULL);
d->t0 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
#endif
}
#ifdef _WIN32
t1 = GetTickCount();
#else
gettimeofday(&tv, NULL);
t1 = tv.tv_sec * 1000 + tv.tv_usec / 1000;
#endif
if (t1 - d->t0 > d->timeout) {
goto done;
}
#ifdef _WIN32
Sleep(10);
#else
#ifdef HAVE_USLEEP
usleep(10000);
#else
tv.tv_sec = 0;
tv.tv_usec = 10000;
select(0, NULL, NULL, NULL, &tv);
#endif
#endif
ret = 1;
done:
return ret;
}
/**
* Set SQLite options (PRAGMAs) given SQLite handle.
* @param x SQLite database handle
* @param d DBC pointer
* @result SQLite error code
*
* SQLite < 3.3.x and not shortnames DSN option:
* "full_column_names" is always turned on and "short_column_names"
* is always turned off, to get the table names in column labels.
*/
static int
setsqliteopts(sqlite3 *x, DBC *d)
{
int count = 0, step = 0, max, rc = SQLITE_ERROR;
#if defined(HAVE_SQLITE3COLUMNTABLENAME) && (HAVE_SQLITE3COLUMNTABLENAME)
max = d->longnames ? 3 : 1;
#else
max = 3;
#endif
if (d->shortnames) {
max = 3;
}
while (step < max) {
if (step < 1) {
rc = sqlite3_exec(x, "PRAGMA empty_result_callbacks = on;",
NULL, NULL, NULL);
} else if (step < 2) {
rc = sqlite3_exec(x, d->shortnames ?
"PRAGMA full_column_names = off;" :
"PRAGMA full_column_names = on;",
NULL, NULL, NULL);
} else if (step < 3) {
rc = sqlite3_exec(x, d->shortnames ?
"PRAGMA short_column_names = on;" :
"PRAGMA short_column_names = off;",
NULL, NULL, NULL);
}
if (rc != SQLITE_OK) {
if (rc != SQLITE_BUSY ||
!busy_handler((void *) d, ++count)) {
return rc;
}
continue;
}
count = 0;
++step;
}
sqlite3_busy_handler(x, busy_handler, (void *) d);
return SQLITE_OK;
}
/**
* Free counted array of char pointers.
* @param rowp pointer to char pointer array
*
* The -1-th element of the array holds the array size.
* All non-NULL pointers of the array and then the array
* itself are free'd.
*/
static void
freerows(char **rowp)
{
PTRDIFF_T size, i;
if (!rowp) {
return;
}
--rowp;
size = (PTRDIFF_T) rowp[0];
for (i = 1; i <= size; i++) {
freep(&rowp[i]);
}
freep(&rowp);
}
/**
* Map SQL field type from string to ODBC integer type code.
* @param typename field type string
* @param nosign pointer to indicator for unsigned field or NULL
* @param ov3 boolean, true for SQL_OV_ODBC3
* @param nowchar boolean, for WINTERFACE don't use WCHAR
* @result SQL data type
*/
static int
mapsqltype(const char *typename, int *nosign, int ov3, int nowchar)
{
char *p, *q;
int testsign = 0, result;
#ifdef WINTERFACE
result = nowchar ? SQL_VARCHAR : SQL_WVARCHAR;
#else
result = SQL_VARCHAR;
#endif
if (!typename) {
return result;
}
q = p = xmalloc(strlen(typename) + 1);
if (!p) {
return result;
}
strcpy(p, typename);
while (*q) {
*q = TOLOWER(*q);
++q;
}
if (strncmp(p, "inter", 5) == 0) {
} else if (strncmp(p, "int", 3) == 0 ||
strncmp(p, "mediumint", 9) == 0) {
testsign = 1;
result = SQL_INTEGER;
} else if (strncmp(p, "numeric", 7) == 0) {
result = SQL_DOUBLE;
} else if (strncmp(p, "tinyint", 7) == 0) {
testsign = 1;
result = SQL_TINYINT;
} else if (strncmp(p, "smallint", 8) == 0) {
testsign = 1;
result = SQL_SMALLINT;
} else if (strncmp(p, "float", 5) == 0) {
result = SQL_DOUBLE;
} else if (strncmp(p, "double", 6) == 0 ||
strncmp(p, "real", 4) == 0) {
result = SQL_DOUBLE;
} else if (strncmp(p, "timestamp", 9) == 0) {
#ifdef SQL_TYPE_TIMESTAMP
result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
#else
result = SQL_TIMESTAMP;
#endif
} else if (strncmp(p, "datetime", 8) == 0) {
#ifdef SQL_TYPE_TIMESTAMP
result = ov3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP;
#else
result = SQL_TIMESTAMP;
#endif
} else if (strncmp(p, "time", 4) == 0) {
#ifdef SQL_TYPE_TIME
result = ov3 ? SQL_TYPE_TIME : SQL_TIME;
#else
result = SQL_TIME;
#endif
} else if (strncmp(p, "date", 4) == 0) {
#ifdef SQL_TYPE_DATE
result = ov3 ? SQL_TYPE_DATE : SQL_DATE;
#else
result = SQL_DATE;
#endif
#ifdef SQL_LONGVARCHAR
} else if (strncmp(p, "text", 4) == 0 ||
strncmp(p, "memo", 4) == 0) {
#ifdef WINTERFACE
result = nowchar ? SQL_LONGVARCHAR : SQL_WLONGVARCHAR;
#else
result = SQL_LONGVARCHAR;
#endif
#ifdef WINTERFACE
} else if (strncmp(p, "wtext", 5) == 0 ||
strncmp(p, "wvarchar", 8) == 0 ||
strncmp(p, "longwvarchar", 12) == 0) {
result = SQL_WLONGVARCHAR;
#endif
#endif
#ifdef SQL_BIT
} else if (strncmp(p, "bool", 4) == 0 ||
strncmp(p, "bit", 3) == 0) {
result = SQL_BIT;
#endif
#ifdef SQL_BIGINT
} else if (strncmp(p, "bigint", 6) == 0) {
result = SQL_BIGINT;
#endif
} else if (strncmp(p, "blob", 4) == 0) {
result = SQL_BINARY;
} else if (strncmp(p, "varbinary", 9) == 0) {
result = SQL_VARBINARY;
} else if (strncmp(p, "longvarbinary", 13) == 0) {
result = SQL_LONGVARBINARY;
}
if (nosign) {
if (testsign) {
*nosign = strstr(p, "unsigned") != NULL;
} else {
*nosign = 1;
}
}
xfree(p);
return result;
}
/**
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -