[q-lang-cvs] q/modules/odbc odbc.c,1.11,1.12 odbc.q,1.6,1.7
Brought to you by:
agraef
From: Albert G. <ag...@us...> - 2008-02-16 06:54:36
|
Update of /cvsroot/q-lang/q/modules/odbc In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv24276 Modified Files: odbc.c odbc.q Log Message: add more ODBC routines to retrieve meta information Index: odbc.q =================================================================== RCS file: /cvsroot/q-lang/q/modules/odbc/odbc.q,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** odbc.q 15 Feb 2008 11:33:22 -0000 1.6 --- odbc.q 16 Feb 2008 06:54:32 -0000 1.7 *************** *** 84,88 **** an integer or a string which can be converted to a Q value using bint or bstr, respectively. See SQLGetInfo() in the ODBC API reference for ! information about which information types are available and which type of information they return. */ --- 84,88 ---- an integer or a string which can be converted to a Q value using bint or bstr, respectively. See SQLGetInfo() in the ODBC API reference for ! information about which information types are available and which types of information they return. */ *************** *** 354,358 **** 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; --- 354,358 ---- Note that fields which don't apply to a given type are left empty, ! indicated by a () a.k.a. NULL value. */ public extern odbc_typeinfo DB TYPE_ID; *************** *** 432,435 **** --- 432,458 ---- SQL_CODE_MINUTE_TO_SECOND = 13; + /* Retrieve information about all tables in the current database. Returns a + list of (NAME,TYPE) string pairs, where NAME denotes the name and TYPE the + type of a table ("TABLE", "VIEW", etc.). */ + + public extern odbc_tables DB; + + /* Retrieve information about the columns of the table with the given name. + Returns a list of string tuples with the following information: NAME + (column name), TYPE (SQL data type), NULLABLE (whether the field is + nullable, "YES" or "NO") and DEFAULT (default value, as a string). The + NULLABLE and DEFAULT values may be () if not available. */ + + public extern odbc_columns DB TABLE_NAME; + + /* Retrieve information about the primary and foreign keys of the given table. + odbc_primary_keys returns the primary keys of the given table as a list of + strings (column names), while odbc_foreign_keys returns a list of string + triples (NAME,PKTAB,PKCOL) where NAME is the name of a column in the given + table with a foreign key which refers to the primary key colum PKCOL in + table PKTAB. */ + + public extern odbc_primary_keys DB TABLE_NAME, odbc_foreign_keys DB TABLE_NAME; + /* 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.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** odbc.c 15 Feb 2008 20:58:12 -0000 1.11 --- odbc.c 16 Feb 2008 06:54:32 -0000 1.12 *************** *** 635,638 **** --- 635,641 ---- #define NMAX 128 + /* Maximum length of string values. */ + #define SL 256 + #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)) *************** *** 649,653 **** 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; --- 652,656 ---- int i, n = 0, m = NMAX; ! UCHAR name[SL], prefix[SL], suffix[SL], params[SL], local_name[SL]; SWORD type, nullable, case_sen, searchable, unsign, money, auto_inc; SWORD min_scale, max_scale; *************** *** 660,669 **** 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]); --- 663,672 ---- sql_close(db); ! ret = SQLBindCol(db->hstmt, 1, SQL_C_CHAR, name, SL, &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, SL, &len[4]); ! ret = SQLBindCol(db->hstmt, 5, SQL_C_CHAR, suffix, SL, &len[5]); ! ret = SQLBindCol(db->hstmt, 6, SQL_C_CHAR, params, SL, &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]); *************** *** 672,676 **** 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]); --- 675,679 ---- 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, SL, &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]); *************** *** 744,747 **** --- 747,1029 ---- } + FUNCTION(odbc,odbc_tables,argc,argv) + { + ODBCHandle *db; + if (argc == 1 && isobj(argv[0], type(ODBCHandle), (void**)&db) && + db->henv) { + expr res, *xs = (expr*)malloc(NMAX*sizeof(expr)), *xs1; + int i, n = 0, m = NMAX; + + UCHAR name[SL], type[SL]; + SDWORD len[6], ret; + + if (!xs) return __ERROR; + sql_close(db); + + ret = SQLBindCol(db->hstmt, 3, SQL_C_CHAR, name, SL, &len[3]); + ret = SQLBindCol(db->hstmt, 4, SQL_C_CHAR, type, SL, &len[4]); + + ret = SQLTables(db->hstmt, NULL, 0, NULL, 0, NULL, 0, NULL,0); + 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(2, + checkstr(name, len[3]), + checkstr(type, len[4])); + break; + case SQL_NO_DATA_FOUND: + break; + default: + goto err; + } + } while (ret != SQL_NO_DATA_FOUND); + SQLFreeStmt(db->hstmt, SQL_RESET_PARAMS); + 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_RESET_PARAMS); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + return res; + fatal: + for (i = 0; i < n; i++) dispose(xs[i]); + free(xs); + SQLFreeStmt(db->hstmt, SQL_RESET_PARAMS); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + return __ERROR; + } else + return __FAIL; + } + + FUNCTION(odbc,odbc_columns,argc,argv) + { + ODBCHandle *db; + char *tab; + if (argc == 2 && isobj(argv[0], type(ODBCHandle), (void**)&db) && + db->henv && isstr(argv[1], &tab)) { + expr res, *xs = (expr*)malloc(NMAX*sizeof(expr)), *xs1; + int i, n = 0, m = NMAX; + + UCHAR name[SL], type[SL], nullable[SL], deflt[SL]; + SDWORD len[19], ret; + + if (!xs) return __ERROR; + tab = from_utf8(tab, NULL); + if (!tab) { free(xs); return __ERROR; } + sql_close(db); + + ret = SQLBindCol(db->hstmt, 4, SQL_C_CHAR, name, SL, &len[4]); + ret = SQLBindCol(db->hstmt, 6, SQL_C_CHAR, type, SL, &len[6]); + ret = SQLBindCol(db->hstmt, 13, SQL_C_CHAR, deflt, SL, &len[13]); + ret = SQLBindCol(db->hstmt, 18, SQL_C_CHAR, nullable, SL, &len[18]); + + ret = SQLColumns(db->hstmt, NULL, 0, NULL, 0, (SQLCHAR*)tab, SQL_NTS, + NULL, 0); + 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(4, + checkstr(name, len[4]), + checkstr(type, len[6]), + checkstr(nullable, len[18]), + checkstr(deflt, len[13])); + break; + case SQL_NO_DATA_FOUND: + break; + default: + goto err; + } + } while (ret != SQL_NO_DATA_FOUND); + SQLFreeStmt(db->hstmt, SQL_RESET_PARAMS); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + free(tab); + 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_RESET_PARAMS); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + free(tab); + return res; + fatal: + for (i = 0; i < n; i++) dispose(xs[i]); + free(xs); + SQLFreeStmt(db->hstmt, SQL_RESET_PARAMS); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + free(tab); + return __ERROR; + } else + return __FAIL; + } + + FUNCTION(odbc,odbc_primary_keys,argc,argv) + { + ODBCHandle *db; + char *tab; + if (argc == 2 && isobj(argv[0], type(ODBCHandle), (void**)&db) && + db->henv && isstr(argv[1], &tab)) { + expr res, *xs = (expr*)malloc(NMAX*sizeof(expr)), *xs1; + int i, n = 0, m = NMAX; + + UCHAR name[SL]; + SDWORD len[5], ret; + + if (!xs) return __ERROR; + tab = from_utf8(tab, NULL); + if (!tab) { free(xs); return __ERROR; } + sql_close(db); + + ret = SQLBindCol(db->hstmt, 4, SQL_C_CHAR, name, SL, &len[4]); + + ret = SQLPrimaryKeys(db->hstmt, NULL, 0, NULL, 0, (SQLCHAR*)tab, SQL_NTS); + 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++] = checkstr(name, len[4]); + break; + case SQL_NO_DATA_FOUND: + break; + default: + goto err; + } + } while (ret != SQL_NO_DATA_FOUND); + SQLFreeStmt(db->hstmt, SQL_RESET_PARAMS); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + free(tab); + 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_RESET_PARAMS); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + free(tab); + return res; + fatal: + for (i = 0; i < n; i++) dispose(xs[i]); + free(xs); + SQLFreeStmt(db->hstmt, SQL_RESET_PARAMS); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + free(tab); + return __ERROR; + } else + return __FAIL; + } + + FUNCTION(odbc,odbc_foreign_keys,argc,argv) + { + ODBCHandle *db; + char *tab; + if (argc == 2 && isobj(argv[0], type(ODBCHandle), (void**)&db) && + db->henv && isstr(argv[1], &tab)) { + expr res, *xs = (expr*)malloc(NMAX*sizeof(expr)), *xs1; + int i, n = 0, m = NMAX; + + UCHAR name[SL], pktabname[SL], pkname[SL]; + SDWORD len[9], ret; + + if (!xs) return __ERROR; + tab = from_utf8(tab, NULL); + if (!tab) { free(xs); return __ERROR; } + sql_close(db); + + ret = SQLBindCol(db->hstmt, 3, SQL_C_CHAR, pktabname, SL, &len[3]); + ret = SQLBindCol(db->hstmt, 4, SQL_C_CHAR, pkname, SL, &len[4]); + ret = SQLBindCol(db->hstmt, 8, SQL_C_CHAR, name, SL, &len[8]); + + ret = SQLForeignKeys(db->hstmt, NULL, 0, NULL, 0, NULL, 0, NULL, 0, + NULL, 0, (SQLCHAR*)tab, SQL_NTS); + 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(3, + checkstr(name, len[8]), + checkstr(pktabname, len[3]), + checkstr(pkname, len[4])); + break; + case SQL_NO_DATA_FOUND: + break; + default: + goto err; + } + } while (ret != SQL_NO_DATA_FOUND); + SQLFreeStmt(db->hstmt, SQL_RESET_PARAMS); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + free(tab); + 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_RESET_PARAMS); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + free(tab); + return res; + fatal: + for (i = 0; i < n; i++) dispose(xs[i]); + free(xs); + SQLFreeStmt(db->hstmt, SQL_RESET_PARAMS); + SQLFreeStmt(db->hstmt, SQL_CLOSE); + free(tab); + return __ERROR; + } else + return __FAIL; + } + #define BUFSZ 65536 #define BUFSZ2 5000 |