[q-lang-cvs] q/modules/odbc odbc.c,1.9,1.10 odbc.q,1.5,1.6
Brought to you by:
agraef
From: Albert G. <ag...@us...> - 2008-02-15 11:33:28
|
Update of /cvsroot/q-lang/q/modules/odbc In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv16634 Modified Files: odbc.c odbc.q Log Message: add odbc_typeinfo function, per request by Tim Haynes Index: odbc.q =================================================================== RCS file: /cvsroot/q-lang/q/modules/odbc/odbc.q,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** odbc.q 14 Feb 2008 00:48:47 -0000 1.5 --- odbc.q 15 Feb 2008 11:33:22 -0000 1.6 *************** *** 318,321 **** --- 318,435 ---- SQL_OJ_CAPABILITIES = 65003; + /* Retrieve information about SQL data types supported by the given data + source. TYPE_ID may be any of the constants listed below. This returns a + list of tuples with the following fields (see SQLGetTypeInfo() in the ODBC + API reference for more information): + + - TYPE_NAME: the name of the type (string) + - DATA_TYPE: a small integer identifying the data type + - PRECISION: maximum precision/column size (integer) + - PREFIX, SUFFIX: characters used as prefixes and suffixes in literals of + the type, respectively (string) + - PARAMS: comma-delimited list of keywords describing the parameters of the + type, in the order in which they have to be specified in a declaration + - NULLABLE: whether the field is nullable (one of the constants + SQL_NO_NULLS, SQL_NULLABLE, SQL_NULLABLE_UNKNOWN defined below) + - CASE_SENSITIVE: whether a character data type is case-sensitive (boolean) + - SEARCHABLE: describes how the data type can be used in SQL where clauses + (one of the SQL_PRED_XXX constants defined below) + - UNSIGNED: whether the data type is unsigned (boolean) + - MONEY: whether the data type has predefined fixed precision, like the + money type (boolean) + - AUTO_INCREMENT: whether the data type is autoincrementing (boolean) + - LOCAL_TYPE_NAME: localized (display) name of the type, if available + (string) + - MINIMUM_SCALE, MAXIMUM_SCALE: minimum and maximum scale of the data type + (integer) + - SQL_DATA_TYPE: SQL data type id (integer); normally, this is the same as + DATA_TYPE, except for interval and datetime data types, where + SQL_DATA_TYPE is either SQL_INTERVAL or SQL_DATETIME, and the + SQL_DATETIME_SUB field (see below) has the datetime/interval subcode + - SQL_DATETIME_SUB: datetime/interval subcode (integer) when SQL_DATA_TYPE + is SQL_INTERVAL or SQL_DATETIME (see above) + - NUM_PREC_RADIX: radix for the precision of numeric types (2 or 10) + - INTERVAL_PRECISION: interval leading precision (integer) when + SQL_DATA_TYPE is SQL_INTERVAL + + Note that fields which don't apply to a given type are left empty, + indicated by a NULL value (() in Q land). */ + + public extern odbc_typeinfo DB TYPE_ID; + + /* Possible values for the TYPE_ID parameter of odbc_typeinfo. Note that some + drivers may support additional codes. Use SQL_ALL_TYPES to retrieve + information for all supported types. */ + + public const var + SQL_ALL_TYPES = 0, + SQL_CHAR = 1, + SQL_NUMERIC = 2, + SQL_DECIMAL = 3, + SQL_INTEGER = 4, + SQL_SMALLINT = 5, + SQL_FLOAT = 6, + SQL_REAL = 7, + SQL_DOUBLE = 8, + SQL_DATE = 9, + SQL_DATETIME = 9, // ODBC 3.x + SQL_TIME = 10, + SQL_INTERVAL = 10, // ODBC 3.x + SQL_TIMESTAMP = 11, + SQL_VARCHAR = 12, + SQL_TYPE_DATE = 91, // ODBC 3.x + SQL_TYPE_TIME = 92, // ODBC 3.x + SQL_TYPE_TIMESTAMP = 93, // ODBC 3.x + SQL_LONGVARCHAR = -1, + SQL_BINARY = -2, + SQL_VARBINARY = -3, + SQL_LONGVARBINARY = -4, + SQL_BIGINT = -5, + SQL_TINYINT = -6, + SQL_BIT = -7, + SQL_GUID = -11; // ODBC 3.x + + /* Possible values of the NULLABLE field. */ + + public const var + SQL_NO_NULLS = 0, + SQL_NULLABLE = 1, + SQL_NULLABLE_UNKNOWN = 2; + + /* Possible values of the SEARCHABLE field. */ + + public const var + SQL_UNSEARCHABLE = 0, + SQL_LIKE_ONLY = 1, + SQL_ALL_EXCEPT_LIKE = 2, + SQL_SEARCHABLE = 3, + // ODBC 3.x synonyms + SQL_PRED_NONE = 0, + SQL_PRED_CHAR = 1, + SQL_PRED_BASIC = 2, + SQL_PRED_SEARCHABLE = 3; + + /* Possible values of the SQL_DATETIME_SUB field (ODBC 3.x). */ + + public const var + // date/time types + SQL_CODE_DATE = 1, + SQL_CODE_TIME = 2, + SQL_CODE_TIMESTAMP = 3, + // interval types + SQL_CODE_YEAR = 1, + SQL_CODE_MONTH = 2, + SQL_CODE_DAY = 3, + SQL_CODE_HOUR = 4, + SQL_CODE_MINUTE = 5, + SQL_CODE_SECOND = 6, + SQL_CODE_YEAR_TO_MONTH = 7, + SQL_CODE_DAY_TO_HOUR = 8, + SQL_CODE_DAY_TO_MINUTE = 9, + SQL_CODE_DAY_TO_SECOND = 10, + SQL_CODE_HOUR_TO_MINUTE = 11, + SQL_CODE_HOUR_TO_SECOND = 12, + SQL_CODE_MINUTE_TO_SECOND = 13; + /* Execute an SQL query and fetch results. SQL queries generally come in two different flavours: queries returning data (so-called result sets), and Index: odbc.c =================================================================== RCS file: /cvsroot/q-lang/q/modules/odbc/odbc.c,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** odbc.c 14 Feb 2008 00:48:47 -0000 1.9 --- odbc.c 15 Feb 2008 11:33:22 -0000 1.10 *************** *** 631,634 **** --- 631,744 ---- } + /* Number of entries in SQLGetTypeInfo() result set. Table entries are + allocated in chunks of this value. */ + #define NMAX 128 + + #define checkstr(s,l) ((l==SQL_NULL_DATA)?mkvoid:mkstr(to_utf8(s, NULL))) + #define checkint(x,l) ((l==SQL_NULL_DATA)?mkvoid:mkint(x)) + #define checkuint(x,l) ((l==SQL_NULL_DATA)?mkvoid:mkuint(x)) + #define checkbool(x,l) ((l==SQL_NULL_DATA)?mkvoid:mkbool(x)) + + FUNCTION(odbc,odbc_typeinfo,argc,argv) + { + ODBCHandle *db; + long id; + if (argc == 2 && isobj(argv[0], type(ODBCHandle), (void**)&db) && + db->henv && isint(argv[1], &id)) { + expr res, *xs = (expr*)malloc(NMAX*sizeof(expr)), *xs1; + int i, n = 0, m = NMAX; + + UCHAR name[80], prefix[80], suffix[80], params[80], local_name[80]; + SWORD type, nullable, case_sen, searchable, unsign, money, auto_inc; + SWORD min_scale, max_scale; + UDWORD prec; + SDWORD len[20], ret; + SWORD sql_type, subcode, intv_prec; + UDWORD prec_radix; + + if (!xs) return __ERROR; + sql_close(db); + + ret = SQLBindCol(db->hstmt, 1, SQL_C_CHAR, name, 80, &len[1]); + ret = SQLBindCol(db->hstmt, 2, SQL_C_SHORT, &type, 0, &len[2]); + ret = SQLBindCol(db->hstmt, 3, SQL_C_LONG, &prec, 0, &len[3]); + ret = SQLBindCol(db->hstmt, 4, SQL_C_CHAR, prefix, 80, &len[4]); + ret = SQLBindCol(db->hstmt, 5, SQL_C_CHAR, suffix, 80, &len[5]); + ret = SQLBindCol(db->hstmt, 6, SQL_C_CHAR, params, 80, &len[6]); + ret = SQLBindCol(db->hstmt, 7, SQL_C_SHORT, &nullable, 0, &len[7]); + ret = SQLBindCol(db->hstmt, 8, SQL_C_SHORT, &case_sen, 0, &len[8]); + ret = SQLBindCol(db->hstmt, 9, SQL_C_SHORT, &searchable, 0, &len[9]); + ret = SQLBindCol(db->hstmt, 10, SQL_C_SHORT, &unsign, 0, &len[10]); + ret = SQLBindCol(db->hstmt, 11, SQL_C_SHORT, &money, 0, &len[11]); + ret = SQLBindCol(db->hstmt, 12, SQL_C_SHORT, &auto_inc, 0, &len[12]); + ret = SQLBindCol(db->hstmt, 13, SQL_C_CHAR, local_name, 80, &len[13]); + ret = SQLBindCol(db->hstmt, 14, SQL_C_SHORT, &min_scale, 0, &len[14]); + ret = SQLBindCol(db->hstmt, 15, SQL_C_SHORT, &max_scale, 0, &len[15]); + ret = SQLBindCol(db->hstmt, 16, SQL_C_SHORT, &sql_type, 0, &len[16]); + ret = SQLBindCol(db->hstmt, 17, SQL_C_SHORT, &subcode, 0, &len[17]); + ret = SQLBindCol(db->hstmt, 18, SQL_C_LONG, &prec_radix, 0, &len[18]); + ret = SQLBindCol(db->hstmt, 19, SQL_C_SHORT, &intv_prec, 0, &len[19]); + + ret = SQLGetTypeInfo(db->hstmt, id); + if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) goto err; + + do { + ret = SQLFetch(db->hstmt); + switch (ret) { + case SQL_SUCCESS_WITH_INFO: + case SQL_SUCCESS: + if (n >= m) + if ((xs1 = (expr*)realloc(xs, (m+=NMAX)*sizeof(expr)))) + xs = xs1; + else + goto fatal; + xs[n++] = mktuplel(19, + checkstr(name, len[1]), + checkint(type, len[2]), + checkuint(prec, len[3]), + checkstr(prefix, len[4]), + checkstr(suffix, len[5]), + checkstr(params, len[6]), + checkint(nullable, len[7]), + checkbool(case_sen, len[8]), + checkint(searchable, len[9]), + checkbool(unsign, len[10]), + checkbool(money, len[11]), + checkbool(auto_inc, len[12]), + checkstr(local_name, len[13]), + checkint(min_scale, len[14]), + checkint(max_scale, len[15]), + checkint(sql_type, len[16]), + checkint(subcode, len[17]), + checkuint(prec_radix, len[18]), + checkint(intv_prec, len[19])); + break; + case SQL_NO_DATA_FOUND: + break; + default: + goto err; + } + } while (ret != SQL_NO_DATA_FOUND); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + if (n == 0) { + free(xs); + return mknil; + } else + return mklistv(n, xs); + err: + for (i = 0; i < n; i++) dispose(xs[i]); + free(xs); + res = mkerr(db->henv, db->hdbc, db->hstmt); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + return res; + fatal: + for (i = 0; i < n; i++) dispose(xs[i]); + free(xs); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + return __ERROR; + } else + return __FAIL; + } + #define BUFSZ 65536 #define BUFSZ2 5000 |