?? sqlite3odbc.c
字號(hào):
* Get maximum display size and number of digits after decimal point
* from field type specification.
* @param typename field type specification
* @param sqltype target SQL data type
* @param mp pointer to maximum display size or NULL
* @param dp pointer to number of digits after decimal point or NULL
*/
static void
getmd(const char *typename, int sqltype, int *mp, int *dp)
{
int m = 0, d = 0;
switch (sqltype) {
case SQL_INTEGER: m = 10; d = 9; break;
case SQL_TINYINT: m = 4; d = 3; break;
case SQL_SMALLINT: m = 6; d = 5; break;
case SQL_FLOAT: m = 25; d = 24; break;
case SQL_DOUBLE: m = 54; d = 53; break;
case SQL_VARCHAR: m = 255; d = 0; break;
#ifdef WINTERFACE
#ifdef SQL_WVARCHAR
case SQL_WVARCHAR: m = 255; d = 0; break;
#endif
#endif
#ifdef SQL_TYPE_DATE
case SQL_TYPE_DATE:
#endif
case SQL_DATE: m = 10; d = 0; break;
#ifdef SQL_TYPE_TIME
case SQL_TYPE_TIME:
#endif
case SQL_TIME: m = 8; d = 0; break;
#ifdef SQL_TYPE_TIMESTAMP
case SQL_TYPE_TIMESTAMP:
#endif
case SQL_TIMESTAMP: m = 32; d = 0; break;
#ifdef SQL_LONGVARCHAR
case SQL_LONGVARCHAR : m = 65536; d = 0; break;
#endif
#ifdef WINTERFACE
#ifdef SQL_WLONGVARCHAR
case SQL_WLONGVARCHAR: m = 65536; d = 0; break;
#endif
#endif
case SQL_VARBINARY: m = 255; d = 0; break;
case SQL_LONGVARBINARY: m = 65536; d = 0; break;
#ifdef SQL_BIGINT
case SQL_BIGINT: m = 20; d = 19; break;
#endif
}
if (m && typename) {
int mm, dd;
if (sscanf(typename, "%*[^(](%d)", &mm) == 1) {
m = d = mm;
} else if (sscanf(typename, "%*[^(](%d,%d)", &mm, &dd) == 2) {
m = mm;
d = dd;
}
}
if (mp) {
*mp = m;
}
if (dp) {
*dp = d;
}
}
/**
* Map SQL_C_DEFAULT to proper C type.
* @param type input C type
* @param stype input SQL type
* @param nosign 0=signed, 0>unsigned, 0<undefined
* @param nowchar when compiled with WINTERFACE don't use WCHAR
* @result C type
*/
static int
mapdeftype(int type, int stype, int nosign, int nowchar)
{
if (type == SQL_C_DEFAULT) {
switch (stype) {
case SQL_INTEGER:
type = (nosign > 0) ? SQL_C_ULONG : SQL_C_LONG;
break;
case SQL_TINYINT:
type = (nosign > 0) ? SQL_C_UTINYINT : SQL_C_TINYINT;
break;
case SQL_SMALLINT:
type = (nosign > 0) ? SQL_C_USHORT : SQL_C_SHORT;
break;
case SQL_FLOAT:
type = SQL_C_FLOAT;
break;
case SQL_DOUBLE:
type = SQL_C_DOUBLE;
break;
case SQL_TIMESTAMP:
type = SQL_C_TIMESTAMP;
break;
case SQL_TIME:
type = SQL_C_TIME;
break;
case SQL_DATE:
type = SQL_C_DATE;
break;
#ifdef SQL_C_TYPE_TIMESTAMP
case SQL_TYPE_TIMESTAMP:
type = SQL_C_TYPE_TIMESTAMP;
break;
#endif
#ifdef SQL_C_TYPE_TIME
case SQL_TYPE_TIME:
type = SQL_C_TYPE_TIME;
break;
#endif
#ifdef SQL_C_TYPE_DATE
case SQL_TYPE_DATE:
type = SQL_C_TYPE_DATE;
break;
#endif
#ifdef WINTERFACE
case SQL_WVARCHAR:
case SQL_WCHAR:
#ifdef SQL_WLONGVARCHAR
case SQL_WLONGVARCHAR:
#endif
type = nowchar ? SQL_C_CHAR : SQL_C_WCHAR;
break;
#endif
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
type = SQL_C_BINARY;
break;
#ifdef SQL_BIT
case SQL_BIT:
type = SQL_C_BIT;
break;
#endif
#ifdef SQL_BIGINT
case SQL_BIGINT:
type = (nosign > 0) ? SQL_C_UBIGINT : SQL_C_SBIGINT;
break;
#endif
default:
#ifdef WINTERFACE
type = SQL_C_WCHAR;
#else
type = SQL_C_CHAR;
#endif
}
}
#ifdef WINTERFACE
if (nowchar) {
if (type == SQL_C_WCHAR) {
type = SQL_C_CHAR;
}
}
#endif
return type;
}
/**
* Fixup query string with optional parameter markers.
* @param sql original query string
* @param sqlLen length of query string or SQL_NTS
* @param nparam output number of parameters
* @param isselect output indicator for SELECT statement
* @param errmsg output error message
* @result newly allocated string containing query string for SQLite or NULL
*/
static char *
fixupsql(char *sql, int sqlLen, int *nparam, int *isselect, char **errmsg)
{
char *q = sql, *qz = NULL, *p, *inq = NULL, *out;
int np = 0, isddl = -1, size;
*errmsg = NULL;
if (sqlLen != SQL_NTS) {
qz = q = xmalloc(sqlLen + 1);
if (!qz) {
return NULL;
}
memcpy(q, sql, sqlLen);
q[sqlLen] = '\0';
size = sqlLen * 4;
} else {
size = strlen(sql) * 4;
}
size += sizeof (char *) - 1;
size &= ~(sizeof (char *) - 1);
p = xmalloc(size);
if (!p) {
errout:
freep(&qz);
return NULL;
}
out = p;
while (*q) {
switch (*q) {
case '\'':
case '\"':
if (q == inq) {
inq = NULL;
} else if (!inq) {
inq = q + 1;
while (*inq) {
if (*inq == *q) {
if (inq[1] == *q) {
inq++;
} else {
break;
}
}
inq++;
}
}
*p++ = *q;
break;
case '?':
*p++ = *q;
if (!inq) {
np++;
}
break;
case ';':
if (!inq) {
if (isddl < 0) {
char *qq = out;
while (*qq && ISSPACE(*qq)) {
++qq;
}
if (*qq && *qq != ';') {
size = strlen(qq);
if ((size >= 5) &&
(strncasecmp(qq, "create", 5) == 0)) {
isddl = 1;
} else if ((size >= 4) &&
(strncasecmp(qq, "drop", 4) == 0)) {
isddl = 1;
} else {
isddl = 0;
}
}
}
if (isddl == 0) {
char *qq = q;
do {
++qq;
} while (*qq && ISSPACE(*qq));
if (*qq && *qq != ';') {
freep(&out);
*errmsg = "only one SQL statement allowed";
goto errout;
}
}
}
*p++ = *q;
break;
case '{':
/* deal with {d 'YYYY-MM-DD'}, {t ...}, and {ts ...} */
if (!inq) {
char *end = q + 1;
while (*end && *end != '}') {
++end;
}
if (*end == '}') {
char *start = q + 1;
char *end2 = end - 1;
while (start < end2 && *start != '\'') {
++start;
}
while (end2 > start && *end2 != '\'') {
--end2;
}
if (*start == '\'' && *end2 == '\'') {
while (start <= end2) {
*p++ = *start;
++start;
}
q = end;
break;
}
}
}
/* FALL THROUGH */
default:
*p++ = *q;
}
++q;
}
freep(&qz);
*p = '\0';
if (nparam) {
*nparam = np;
}
if (isselect) {
if (isddl > 0) {
*isselect = 0;
} else {
p = out;
while (*p && ISSPACE(*p)) {
++p;
}
size = strlen(p);
*isselect = (size >= 6) && (strncasecmp(p, "select", 6) == 0);
}
}
return out;
}
/**
* Find column given name in string array.
* @param cols string array
* @param ncols number of strings
* @param name column name
* @result >= 0 on success, -1 on error
*/
static int
findcol(char **cols, int ncols, char *name)
{
int i;
if (cols) {
for (i = 0; i < ncols; i++) {
if (strcmp(cols[i], name) == 0) {
return i;
}
}
}
return -1;
}
/**
* Fixup column information for a running statement.
* @param s statement to get fresh column information
* @param d DBC pointer
*
* The column labels get the table names stripped
* when there's more than one column and all table
* names are identical.
*
* The "dyncols" field of STMT is filled with column
* information obtained by SQLite "PRAGMA table_info"
* for each column whose table name is known. If the
* types are already present as with SQLite 2.5.7
* this information is used instead.
*/
static void
fixupdyncols(STMT *s, DBC *d)
{
int i, k, pk, nn, t, r, nrows, ncols;
char **rowp, *flagp, flags[128];
if (!s->dyncols) {
return;
}
/* fixup labels */
if (!s->longnames) {
if (s->dcols > 1) {
char *table = s->dyncols[0].table;
for (i = 1; table[0] && i < s->dcols; i++) {
if (strcmp(s->dyncols[i].table, table)) {
break;
}
}
if (i >= s->dcols) {
for (i = 0; i < s->dcols; i++) {
s->dyncols[i].label = s->dyncols[i].column;
}
}
} else if (s->dcols == 1) {
s->dyncols[0].label = s->dyncols[0].column;
}
}
for (i = 0; i < s->dcols; i++) {
s->dyncols[i].type =
mapsqltype(s->dyncols[i].typename, &s->dyncols[i].nosign, *s->ov3,
s->nowchar[0] || s->nowchar[1]);
getmd(s->dyncols[i].typename, s->dyncols[i].type,
&s->dyncols[i].size, NULL);
#ifdef SQL_LONGVARCHAR
if (s->dyncols[i].type == SQL_VARCHAR &&
s->dyncols[i].size > 255) {
s->dyncols[i].type = SQL_LONGVARCHAR;
}
#endif
#ifdef WINTERFACE
#ifdef SQL_WLONGVARCHAR
if (s->dyncols[i].type == SQL_WVARCHAR &&
s->dyncols[i].size > 255) {
s->dyncols[i].type = SQL_WLONGVARCHAR;
}
#endif
#endif
if (s->dyncols[i].type == SQL_VARBINARY &&
s->dyncols[i].size > 255) {
s->dyncols[i].type = SQL_LONGVARBINARY;
}
}
if (s->dcols > array_size(flags)) {
flagp = xmalloc(sizeof (flags[0]) * s->dcols);
if (flagp == NULL) {
return;
}
} else {
flagp = flags;
}
memset(flagp, 0, sizeof (flags[0]) * s->dcols);
for (i = 0; i < s->dcols; i++) {
s->dyncols[i].autoinc = SQL_FALSE;
s->dyncols[i].notnull = SQL_NULLABLE;
}
for (i = 0; i < s->dcols; i++) {
int ret, lastpk = -1, autoinccount = 0;
char *sql;
if (!s->dyncols[i].table[0]) {
continue;
}
if (flagp[i]) {
continue;
}
sql = sqlite3_mprintf("PRAGMA table_info(%Q)", s->dyncols[i].table);
if (!sql) {
continue;
}
dbtraceapi(d, "sqlite3_get_table", sql);
ret = sqlite3_get_table(d->sqlite, sql, &rowp, &nrows, &ncols, NULL);
sqlite3_free(sql);
if (ret != SQLITE_OK) {
continue;
}
k = findcol(rowp, ncols, "name");
t = findcol(rowp, ncols, "type");
pk = findcol(rowp, ncols, "pk");
nn = findcol(rowp, ncols, "notnull");
if (k < 0 || t < 0) {
goto freet;
}
for (r = 1; r <= nrows; r++) {
int m;
for (m = i; m < s->dcols; m++) {
char *colname = s->dyncols[m].column;
if (s->longnames) {
char *dotp = strchr(colname, '.');
if (dotp) {
colname = dotp + 1;
}
}
if (!flagp[m] &&
strcmp(colname, rowp[r * ncols + k]) == 0 &&
strcmp(s->dyncols[m].table, s->dyncols[i].table) == 0) {
char *typename = rowp[r * ncols + t];
flagp[m] = 1;
freep(&s->dyncols[m].typename);
s->dyncols[m].typename = xstrdup(typename);
s->dyncols[m].type =
mapsqltype(typename, &s->dyncols[m].nosign, *s->ov3,
s->nowchar[0] || s->nowchar[1]);
getmd(typename, s->dyncols[m].type, &s->dyncols[m].size,
NULL);
#ifdef SQL_LONGVARCHAR
if (s->dyncols[m].type == SQL_VARCHAR &&
s->dyncols[m].size > 255) {
s->dyncols[m].type = SQL_LONGVARCHAR;
}
#endif
#ifdef WINTERFACE
#ifdef SQL_WLONGVARCHAR
if (s->dyncols[i].type == SQL_WVARCHAR &&
s->dyncols[i].size > 255) {
s->dyncols[i].type = SQL_WLONGVARCHAR;
}
#endif
#endif
if (s->dyncols[i].type == SQL_VARBINARY &&
s->dyncols[i].size > 255) {
s->dyncols[i].type = SQL_LONGVARBINARY;
}
if (pk >= 0 && strcmp(rowp[r * ncols + pk], "1") == 0) {
if (++autoinccount > 1) {
if (lastpk >= 0) {
s->dyncols[lastpk].autoinc = SQL_FALSE;
lastpk = -1;
}
} else {
lastpk = m;
if (strlen(typename) == 7 &&
strncasecmp(typename, "integer", 7) == 0) {
s->dyncols[m].autoinc = SQL_TRUE;
}
}
}
if (nn >= 0 && rowp[r * ncols + nn][0] != '0') {
s->dyncols[m].notnull = SQL_NO_NULLS;
}
}
}
}
freet:
sqlite3_free_table(rowp);
}
if (flagp != flags) {
freep(&flagp);
}
}
/**
* Return number of month days.
* @param year
* @param month 1..12
* @result number of month days or 0
*/
static int
getmdays(int year, int month)
{
static const int mdays[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int mday;
if (month < 1) {
return 0;
}
mday = mdays[(month - 1) % 12];
if (mday == 28 && year % 4 == 0 &&
(!(year % 100 == 0) || year % 400 == 0)) {
mday++;
}
return mday;
}
/**
* Convert string to ODBC DATE_STRUCT.
* @param str string to be converted
* @param ds output DATE_STRUCT
* @result 0 on success, -1 on error
*
* Strings of the format 'YYYYMMDD' or 'YYYY-MM-DD' or
* 'YYYY/MM/DD' are converted to a DATE_STRUCT.
*/
static int
str2date(char *str, DATE_STRUCT *ds)
{
int i, err = 0;
char *p, *q;
ds->year = ds->month = ds->day = 0;
p = str;
while (*p && !ISDIGIT(*p)) {
++p;
}
q = p;
i = 0;
while (*q && !ISDIGIT(*q)) {
++i;
++q;
}
if (i >= 8) {
char buf[8];
strncpy(buf, p + 0, 4); buf[4] = '\0';
ds->year = strtol(buf, NULL, 10);
strncpy(buf, p + 4, 2); buf[2] = '\0';
ds->month = strtol(buf, NULL, 10);
strncpy(buf, p + 6, 2); buf[2] = '\0';
ds->day = strtol(buf, NULL, 10);
goto done;
}
i = 0;
while (i < 3) {
int n;
q = NULL;
n = strtol(p, &q, 10);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -