From 955de52c9c3ba26509126bb35af787d1adabdf5a Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Fri, 10 Feb 2006 02:27:42 +0000 Subject: [PATCH] Add the column_origin_name() etc. APIs. (CVS 3069) FossilOrigin-Name: 82f502cdc1fead3bf7e3190d5c9db3aee6919ed4 --- manifest | 44 +++++++------- manifest.uuid | 2 +- src/btree.c | 6 +- src/delete.c | 4 +- src/insert.c | 4 +- src/parse.y | 4 +- src/pragma.c | 61 +++++++++---------- src/prepare.c | 18 +++--- src/select.c | 152 ++++++++++++++++++++++++++++++++++++------------ src/sqlite.h.in | 27 ++++++++- src/tclsqlite.c | 5 +- src/test1.c | 10 +++- src/update.c | 4 +- src/vdbe.h | 15 ++++- src/vdbeapi.c | 32 ++++++---- src/vdbeaux.c | 13 +++-- test/capi2.test | 79 ++++++++++++++++++++++++- test/capi3.test | 93 ++++++++++++++++++++++++++++- 18 files changed, 436 insertions(+), 137 deletions(-) diff --git a/manifest b/manifest index 6fbe27c0cd..a9e5da37d0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Ignore\serrors\swhen\swhen\scalling\sfsync()\son\sa\sdirectory.\s\sTicket\s#1657.\s(CVS\s3068) -D 2006-02-09T23:05:51 +C Add\sthe\scolumn_origin_name()\setc.\sAPIs.\s(CVS\s3069) +D 2006-02-10T02:27:42 F Makefile.in 5d8dff443383918b700e495de42ec65bc1c8865b F Makefile.linux-gcc 74ba0eadf88748a9ce3fd03d2a3ede2e6715baec F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -34,19 +34,19 @@ F src/alter.c 451b34fc4eb2475ca76a2e86b21e1030a9428091 F src/analyze.c 7d2b7ab9a9c2fd6e55700f69064dfdd3e36d7a8a F src/attach.c d73a3505de3fb9e373d0a158978116c4212031d0 F src/auth.c 9ae84d2d94eb96195e04515715e08e85963e96c2 -F src/btree.c f45f57e6cbd3b3db947cdd699db64e5215d20b2a +F src/btree.c 66112ae6a5caab384010344b514e98b346f550c0 F src/btree.h 5663c4f43e8521546ccebc8fc95acb013b8f3184 F src/build.c d959aa9c2ab9c79d3d872ce91ef719698658210c F src/callback.c 1bf497306c32229114f826707054df7ebe10abf2 F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675 F src/date.c cd2bd5d1ebc6fa12d6312f69789ae5b0a2766f2e -F src/delete.c 56ab34c3a384caa5d5ea06f5739944957e2e4213 +F src/delete.c ca404d5fd5f678e32f2f46377ad802cd0219aa99 F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b F src/expr.c 1149c3380bfce27703f5e9bec7dfb8e51baaf9d9 F src/func.c 93d004b453a5d9aa754e673eef75d3c9527e0f54 F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 -F src/insert.c 7e931b7f06afbcefcbbaab175c02eff8268db33f +F src/insert.c 67b3dc11831c58d8703eb502355ad3704ee18f66 F src/legacy.c 86b669707b3cefd570e34154e2f6457547d1df4f F src/main.c 9a42464c44a6532003391486e802e65e88789cfc F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 @@ -61,19 +61,19 @@ F src/os_win.c c67a2c46d929cf54c8f80ec5e6079cf684a141a9 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c b5b380ea7a36f84e50c3adc1a414820a0eb3baa6 F src/pager.h e0acb095b3ad0bca48f2ab00c87346665643f64f -F src/parse.y ce7182bfd47b7e5921bc55dcc399cda5cb879f19 -F src/pragma.c c26c810e9c7d3a95a2c617b507bf8e8d65be7721 -F src/prepare.c 40ae23c8aeb641dc7b9bb271eb5e295b815154a7 +F src/parse.y 6d666d60a3bb51ceeb0d30b395455a24856849b7 +F src/pragma.c 8e135979702f249dd5877402056df0a336ea5a12 +F src/prepare.c cf0fc8ebaf94409955ecb09ffeb0099c9ef44693 F src/printf.c c7d6ad9efb71c466305297a448308f467b6e2b6e F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261 -F src/select.c daee9b20702ba51cf3807fc1b130edd8846e3e48 +F src/select.c ace67e13cd1344aa8de552c8eab9bce58f97ec24 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c 738f55ed75fb36731e764bfdb40756ac43b90b08 -F src/sqlite.h.in 89120d384e949be60f36af0e9e9f1b2684a30d35 +F src/sqlite.h.in 7a76811fe3743522b531994dfbf90f24b2333f71 F src/sqliteInt.h 0121298397ac14eb468ab1ba9d488ac7ed7d88a1 F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316 -F src/tclsqlite.c 7764ab34df617b3d3cfd5f0fdf3444ed219c11d6 -F src/test1.c 894df7bced48bd30be04ab9990350900ae33557d +F src/tclsqlite.c d9c26374b52cd47233ae0620d0a858a59b601f89 +F src/test1.c 58ab748e96754f2e05c85282ac47f81f7b8c44a3 F src/test2.c ca74a1d8aeb7d9606e8f6b762c5daf85c1a3f92b F src/test3.c 86e99724ee898b119ed575ef9f98618afe7e5e5d F src/test4.c ff4e9406b3d2809966d8f0e82468ac5508be9f56 @@ -85,15 +85,15 @@ F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3 F src/test_server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/tokenize.c 382b3bb0ca26eb9153b5d20b246ef512a114a24f F src/trigger.c 4d3644cbd16959b568c95ae73493402be8021b08 -F src/update.c 14be4ba2f438919b4217085c02feff569e6cf1f2 +F src/update.c 050a7e0ddaac03dec5271712eee62f1a9e699049 F src/utf.c 1199766bbb0157931a83aa6eede6b6381177be64 F src/util.c 405f46fef062b476826d2c171ec21def29563b75 F src/vacuum.c 3865673cc66acd0717ecd517f6b8fdb2a5e7924b F src/vdbe.c c92d7a4d3476136b8ab440f1e0547fab24112b34 -F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13 +F src/vdbe.h 12e2326f256db62352f10764d1a3940d914ded59 F src/vdbeInt.h eb3f86ab08ef11635bc78eb88c3ff13f923c233b -F src/vdbeapi.c 54dfd0975151c859ec5b125d225ad5b3cb586497 -F src/vdbeaux.c 9bf50cdb6a6c40b8c06ca9a8d87cf90120a16797 +F src/vdbeapi.c 72569c560acfba3e961b3cc9245a79647ea7c5ea +F src/vdbeaux.c 95f4ed0bc8ed45f16823d84504310495b5dc587d F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5 F src/vdbemem.c 2034e93b32c14bda6e306bb54e3a8e930b963027 F src/where.c c7d71d5e55c9c4c1e948089280fb0dec7c7d1ef6 @@ -131,8 +131,8 @@ F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027 F test/btree7.test a6d3b842db22af97dd14b989e90a2fd96066b72f F test/btree8.test fadc112bcbd6a0c622d34c813fc8a648eacf8804 F test/busy.test 0271c854738e23ad76e10d4096a698e5af29d211 -F test/capi2.test b9354d6c37e6f8f858c08952ebc9709712581221 -F test/capi3.test f36912f21457fa713ace874e73f2b54d55d1b9dd +F test/capi2.test ca76487c525b4e6085b9766cc02bcfcc53835f73 +F test/capi3.test e26c09ec40c5dddf215c5dd359b4989a53dde876 F test/capi3b.test 5f0bc94b104e11086b1103b20277e1910f59c7f4 F test/cast.test aabdcb3873bb2f40d855bf63950f6d99a5a196c7 F test/check.test 55ad950d7ad24d6eb3328c54149f90d38a39a962 @@ -351,7 +351,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 0738ef818d4023a5159b6bee0a65f0b83d01c1d5 -R 9d82f47f56b8d05740c30b2797755d9b -U drh -Z ed0151d0fbc7fcca110e9a3939d74452 +P d54d3b82c468b7e6dd39aac6aac56b26b3918c37 +R 0b8bfdc13fc109c03d9eefa67aff0e14 +U danielk1977 +Z a17c7aa8ab9c9bcf9b5fa8f511de465d diff --git a/manifest.uuid b/manifest.uuid index ed3e57245a..a2704a4219 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d54d3b82c468b7e6dd39aac6aac56b26b3918c37 \ No newline at end of file +82f502cdc1fead3bf7e3190d5c9db3aee6919ed4 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index f0e749302f..ea6339f0a6 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.311 2006/01/24 16:37:58 danielk1977 Exp $ +** $Id: btree.c,v 1.312 2006/02/10 02:27:42 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -411,8 +411,8 @@ struct BtCursor { ** The table that this cursor was opened on still exists, but has been ** modified since the cursor was last used. The cursor position is saved ** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in -** this state, restoreOrClearCursorPosition() can be called to attempt to seek -** the cursor to the saved position. +** this state, restoreOrClearCursorPosition() can be called to attempt to +** seek the cursor to the saved position. */ #define CURSOR_INVALID 0 #define CURSOR_VALID 1 diff --git a/src/delete.c b/src/delete.c index f1b73a93a7..85054acb96 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** -** $Id: delete.c,v 1.120 2006/01/24 12:09:19 danielk1977 Exp $ +** $Id: delete.c,v 1.121 2006/02/10 02:27:43 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -343,7 +343,7 @@ void sqlite3DeleteFrom( if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){ sqlite3VdbeAddOp(v, OP_Callback, 1, 0); sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, "rows deleted", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC); } delete_from_cleanup: diff --git a/src/insert.c b/src/insert.c index 7899610e25..3029db3a4a 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.160 2006/01/24 12:09:19 danielk1977 Exp $ +** $Id: insert.c,v 1.161 2006/02/10 02:27:43 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -703,7 +703,7 @@ void sqlite3Insert( sqlite3VdbeAddOp(v, OP_MemLoad, iCntMem, 0); sqlite3VdbeAddOp(v, OP_Callback, 1, 0); sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, "rows inserted", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", P3_STATIC); } insert_cleanup: diff --git a/src/parse.y b/src/parse.y index 6c3da0dbee..106fda0363 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.194 2006/01/30 23:04:51 drh Exp $ +** @(#) $Id: parse.y,v 1.195 2006/02/10 02:27:43 danielk1977 Exp $ */ // All token codes are small integers with #defines that begin with "TK_" @@ -476,7 +476,7 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). { } } - // A seltablist_paren nonterminal represents anything in a FROM that + // A seltablist_paren nonterminal represents anything in a FROM that // is contained inside parentheses. This can be either a subquery or // a grouping of table and subqueries. // diff --git a/src/pragma.c b/src/pragma.c index d4002c9c34..56a9a9cb2f 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.116 2006/02/09 16:52:24 drh Exp $ +** $Id: pragma.c,v 1.117 2006/02/10 02:27:43 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -128,7 +128,7 @@ static void returnSingleInt(Parse *pParse, const char *zLabel, int value){ sqlite3VdbeAddOp(v, OP_Integer, value, 0); if( pParse->explain==0 ){ sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, zLabel, P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, P3_STATIC); } sqlite3VdbeAddOp(v, OP_Callback, 1, 0); } @@ -274,7 +274,7 @@ void sqlite3Pragma( if( sqlite3ReadSchema(pParse) ) goto pragma_out; if( !zRight ){ sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, "cache_size", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", P3_STATIC); addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize); sqlite3VdbeChangeP1(v, addr, iDb); sqlite3VdbeChangeP1(v, addr+5, MAX_PAGES); @@ -392,7 +392,8 @@ void sqlite3Pragma( if( !zRight ){ if( sqlite3_temp_directory ){ sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, "temp_store_directory", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, + "temp_store_directory", P3_STATIC); sqlite3VdbeOp3(v, OP_String8, 0, 0, sqlite3_temp_directory, 0); sqlite3VdbeAddOp(v, OP_Callback, 1, 0); } @@ -470,12 +471,12 @@ void sqlite3Pragma( int i; Column *pCol; sqlite3VdbeSetNumCols(v, 6); - sqlite3VdbeSetColName(v, 0, "cid", P3_STATIC); - sqlite3VdbeSetColName(v, 1, "name", P3_STATIC); - sqlite3VdbeSetColName(v, 2, "type", P3_STATIC); - sqlite3VdbeSetColName(v, 3, "notnull", P3_STATIC); - sqlite3VdbeSetColName(v, 4, "dflt_value", P3_STATIC); - sqlite3VdbeSetColName(v, 5, "pk", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", P3_STATIC); + sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC); + sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", P3_STATIC); + sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", P3_STATIC); + sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", P3_STATIC); + sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", P3_STATIC); sqlite3ViewGetColumnNames(pParse, pTab); for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ sqlite3VdbeAddOp(v, OP_Integer, i, 0); @@ -499,9 +500,9 @@ void sqlite3Pragma( int i; pTab = pIdx->pTable; sqlite3VdbeSetNumCols(v, 3); - sqlite3VdbeSetColName(v, 0, "seqno", P3_STATIC); - sqlite3VdbeSetColName(v, 1, "cid", P3_STATIC); - sqlite3VdbeSetColName(v, 2, "name", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", P3_STATIC); + sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", P3_STATIC); + sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", P3_STATIC); for(i=0; inColumn; i++){ int cnum = pIdx->aiColumn[i]; sqlite3VdbeAddOp(v, OP_Integer, i, 0); @@ -524,9 +525,9 @@ void sqlite3Pragma( if( pIdx ){ int i = 0; sqlite3VdbeSetNumCols(v, 3); - sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC); - sqlite3VdbeSetColName(v, 1, "name", P3_STATIC); - sqlite3VdbeSetColName(v, 2, "unique", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC); + sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC); + sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", P3_STATIC); while(pIdx){ sqlite3VdbeAddOp(v, OP_Integer, i, 0); sqlite3VdbeOp3(v, OP_String8, 0, 0, pIdx->zName, 0); @@ -543,9 +544,9 @@ void sqlite3Pragma( int i; if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3VdbeSetNumCols(v, 3); - sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC); - sqlite3VdbeSetColName(v, 1, "name", P3_STATIC); - sqlite3VdbeSetColName(v, 2, "file", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC); + sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC); + sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", P3_STATIC); for(i=0; inDb; i++){ if( db->aDb[i].pBt==0 ) continue; assert( db->aDb[i].zName!=0 ); @@ -561,8 +562,8 @@ void sqlite3Pragma( int i = 0; HashElem *p; sqlite3VdbeSetNumCols(v, 2); - sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC); - sqlite3VdbeSetColName(v, 1, "name", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P3_STATIC); + sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P3_STATIC); for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){ CollSeq *pColl = (CollSeq *)sqliteHashData(p); sqlite3VdbeAddOp(v, OP_Integer, i++, 0); @@ -584,11 +585,11 @@ void sqlite3Pragma( if( pFK ){ int i = 0; sqlite3VdbeSetNumCols(v, 5); - sqlite3VdbeSetColName(v, 0, "id", P3_STATIC); - sqlite3VdbeSetColName(v, 1, "seq", P3_STATIC); - sqlite3VdbeSetColName(v, 2, "table", P3_STATIC); - sqlite3VdbeSetColName(v, 3, "from", P3_STATIC); - sqlite3VdbeSetColName(v, 4, "to", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P3_STATIC); + sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P3_STATIC); + sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P3_STATIC); + sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", P3_STATIC); + sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", P3_STATIC); while(pFK){ int j; for(j=0; jnCol; j++){ @@ -650,7 +651,7 @@ void sqlite3Pragma( /* Initialize the VDBE program */ if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC); sqlite3VdbeAddOp(v, OP_MemInt, 0, 0); /* Initialize error count to 0 */ /* Do an integrity check on each database file */ @@ -795,7 +796,7 @@ void sqlite3Pragma( if( !zRight ){ /* "PRAGMA encoding" */ if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, "encoding", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", P3_STATIC); sqlite3VdbeAddOp(v, OP_String8, 0, 0); for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ if( pEnc->enc==ENC(pParse->db) ){ @@ -901,8 +902,8 @@ void sqlite3Pragma( int i; Vdbe *v = sqlite3GetVdbe(pParse); sqlite3VdbeSetNumCols(v, 2); - sqlite3VdbeSetColName(v, 0, "database", P3_STATIC); - sqlite3VdbeSetColName(v, 1, "status", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", P3_STATIC); + sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", P3_STATIC); for(i=0; inDb; i++){ Btree *pBt; Pager *pPager; diff --git a/src/prepare.c b/src/prepare.c index 16e354f0f4..c755d6b93e 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -13,7 +13,7 @@ ** interface, and routines that contribute to loading the database schema ** from disk. ** -** $Id: prepare.c,v 1.30 2006/01/30 22:35:44 drh Exp $ +** $Id: prepare.c,v 1.31 2006/02/10 02:27:43 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -556,16 +556,16 @@ int sqlite3_prepare( if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ if( sParse.explain==2 ){ sqlite3VdbeSetNumCols(sParse.pVdbe, 3); - sqlite3VdbeSetColName(sParse.pVdbe, 0, "order", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 1, "from", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 2, "detail", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "order", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "from", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "detail", P3_STATIC); }else{ sqlite3VdbeSetNumCols(sParse.pVdbe, 5); - sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 2, "p1", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC); - sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 0, COLNAME_NAME, "addr", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 1, COLNAME_NAME, "opcode", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 2, COLNAME_NAME, "p1", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 3, COLNAME_NAME, "p2", P3_STATIC); + sqlite3VdbeSetColName(sParse.pVdbe, 4, COLNAME_NAME, "p3", P3_STATIC); } } #endif diff --git a/src/select.c b/src/select.c index 14d8a00c14..4a3cdf74f7 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.301 2006/01/24 12:09:19 danielk1977 Exp $ +** $Id: select.c,v 1.302 2006/02/10 02:27:43 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -762,14 +762,31 @@ static void generateSortTail( ** Return a pointer to a string containing the 'declaration type' of the ** expression pExpr. The string may be treated as static by the caller. ** -** If the declaration type is the exact datatype definition extracted from -** the original CREATE TABLE statement if the expression is a column. +** The declaration type is the exact datatype definition extracted from the +** original CREATE TABLE statement if the expression is a column. The +** declaration type for a ROWID field is INTEGER. Exactly when an expression +** is considered a column can be complex in the presence of subqueries. The +** result-set expression in all of the following SELECT statements is +** considered a column by this function. +** +** SELECT col FROM tbl; +** SELECT (SELECT col FROM tbl; +** SELECT (SELECT col FROM tbl); +** SELECT abc FROM (SELECT col AS abc FROM tbl); ** -** The declaration type for an expression is either TEXT, NUMERIC or ANY. -** The declaration type for a ROWID field is INTEGER. +** The declaration type for any expression other than a column is NULL. */ -static const char *columnType(NameContext *pNC, Expr *pExpr){ - char const *zType; +static const char *columnType( + NameContext *pNC, + Expr *pExpr, + const char **pzOriginDb, + const char **pzOriginTab, + const char **pzOriginCol +){ + char const *zType = 0; + char const *zOriginDb = 0; + char const *zOriginTab = 0; + char const *zOriginCol = 0; int j; if( pExpr==0 || pNC->pSrcList==0 ) return 0; @@ -781,17 +798,24 @@ static const char *columnType(NameContext *pNC, Expr *pExpr){ switch( pExpr->op ){ case TK_COLUMN: { - Table *pTab = 0; - int iCol = pExpr->iColumn; + /* The expression is a column. Locate the table the column is being + ** extracted from in NameContext.pSrcList. This table may be real + ** database table or a subquery. + */ + Table *pTab = 0; /* Table structure column is extracted from */ + Select *pS = 0; /* Select the column is extracted from */ + int iCol = pExpr->iColumn; /* Index of column in pTab */ while( pNC && !pTab ){ SrcList *pTabList = pNC->pSrcList; for(j=0;jnSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++); if( jnSrc ){ pTab = pTabList->a[j].pTab; + pS = pTabList->a[j].pSelect; }else{ pNC = pNC->pNext; } } + if( pTab==0 ){ /* FIX ME: ** This can occurs if you have something like "SELECT new.x;" inside @@ -806,30 +830,72 @@ static const char *columnType(NameContext *pNC, Expr *pExpr){ zType = "TEXT"; break; } + assert( pTab ); - if( iCol<0 ) iCol = pTab->iPKey; - assert( iCol==-1 || (iCol>=0 && iColnCol) ); - if( iCol<0 ){ - zType = "INTEGER"; - }else{ - zType = pTab->aCol[iCol].zType; +#ifndef SQLITE_OMIT_SUBQUERY + if( pS ){ + /* The "table" is actually a sub-select or a view in the FROM clause + ** of the SELECT statement. Return the declaration type and origin + ** data for the result-set column of the sub-select. + */ + if( iCol>=0 && iColpEList->nExpr ){ + /* If iCol is less than zero, then the expression requests the + ** rowid of the sub-select or view. This expression is legal (see + ** test case misc2.2.2) - it always evaluates to NULL. + */ + NameContext sNC; + Expr *p = pS->pEList->a[iCol].pExpr; + sNC.pSrcList = pS->pSrc; + sNC.pNext = 0; + sNC.pParse = pNC->pParse; + zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol); + } + }else +#endif + if( pTab->pSchema ){ + /* A real table */ + assert( !pS ); + if( iCol<0 ) iCol = pTab->iPKey; + assert( iCol==-1 || (iCol>=0 && iColnCol) ); + if( iCol<0 ){ + zType = "INTEGER"; + zOriginCol = "rowid"; + }else{ + zType = pTab->aCol[iCol].zType; + zOriginCol = pTab->aCol[iCol].zName; + } + zOriginTab = pTab->zName; + if( pNC->pParse ){ + int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema); + zOriginDb = pNC->pParse->db->aDb[iDb].zName; + } } break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_SELECT: { + /* The expression is a sub-select. Return the declaration type and + ** origin info for the single column in the result set of the SELECT + ** statement. + */ NameContext sNC; Select *pS = pExpr->pSelect; - sNC.pSrcList = pExpr->pSelect->pSrc; + Expr *p = pS->pEList->a[0].pExpr; + sNC.pSrcList = pS->pSrc; sNC.pNext = pNC; - zType = columnType(&sNC, pS->pEList->a[0].pExpr); + sNC.pParse = pNC->pParse; + zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol); break; } #endif - default: - zType = 0; } + if( pzOriginDb ){ + assert( pzOriginTab && pzOriginCol ); + *pzOriginDb = zOriginDb; + *pzOriginTab = zOriginTab; + *pzOriginCol = zOriginCol; + } return zType; } @@ -846,14 +912,27 @@ static void generateColumnTypes( int i; NameContext sNC; sNC.pSrcList = pTabList; + sNC.pParse = pParse; for(i=0; inExpr; i++){ Expr *p = pEList->a[i].pExpr; - const char *zType = columnType(&sNC, p); - if( zType==0 ) continue; + const char *zOrigDb = 0; + const char *zOrigTab = 0; + const char *zOrigCol = 0; + const char *zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); + /* The vdbe must make it's own copy of the column-type, in case the ** schema is reset before this virtual machine is deleted. + ** + ** TODO: Create some symbol that is better than "-20" to pass to + ** sqlite3VdbeSetColName(). As is this is a ticking bomb. An alternative + ** is to pass the length of the string, but that means calling strlen() + ** here which consumes code space. By passing a negative value that is + ** not P3_DYNAMIC or P3_STATIC, strlen() is called by VdbeSetColName(). */ - sqlite3VdbeSetColName(v, i+pEList->nExpr, zType, strlen(zType)); + sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, -20); + sqlite3VdbeSetColName(v, i, COLNAME_DATABASE, zOrigDb, -20); + sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, -20); + sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, -20); } } @@ -891,7 +970,7 @@ static void generateColumnNames( if( p==0 ) continue; if( pEList->a[i].zName ){ char *zName = pEList->a[i].zName; - sqlite3VdbeSetColName(v, i, zName, strlen(zName)); + sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, strlen(zName)); continue; } if( p->op==TK_COLUMN && pTabList ){ @@ -909,7 +988,7 @@ static void generateColumnNames( zCol = pTab->aCol[iCol].zName; } if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){ - sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n); + sqlite3VdbeSetColName(v, i, COLNAME_NAME, (char*)p->span.z, p->span.n); }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){ char *zName = 0; char *zTab; @@ -917,18 +996,18 @@ static void generateColumnNames( zTab = pTabList->a[j].zAlias; if( fullNames || zTab==0 ) zTab = pTab->zName; sqlite3SetString(&zName, zTab, ".", zCol, (char*)0); - sqlite3VdbeSetColName(v, i, zName, P3_DYNAMIC); + sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, P3_DYNAMIC); }else{ - sqlite3VdbeSetColName(v, i, zCol, strlen(zCol)); + sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, strlen(zCol)); } }else if( p->span.z && p->span.z[0] ){ - sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n); + sqlite3VdbeSetColName(v, i, COLNAME_NAME, (char*)p->span.z, p->span.n); /* sqlite3VdbeCompressSpace(v, addr); */ }else{ char zName[30]; assert( p->op!=TK_COLUMN || pTabList==0 ); sprintf(zName, "column%d", i+1); - sqlite3VdbeSetColName(v, i, zName, 0); + sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, 0); } } generateColumnTypes(pParse, pTabList, pEList); @@ -1036,7 +1115,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ */ memset(&sNC, 0, sizeof(sNC)); sNC.pSrcList = pSelect->pSrc; - zType = sqliteStrDup(columnType(&sNC, p)); + zType = sqliteStrDup(columnType(&sNC, p, 0, 0, 0)); pCol->zType = zType; pCol->affinity = sqlite3ExprAffinity(p); pColl = sqlite3ExprCollSeq(pParse, p); @@ -2783,13 +2862,6 @@ int sqlite3Select( v = sqlite3GetVdbe(pParse); if( v==0 ) goto select_end; - /* Identify column names if we will be using them in a callback. This - ** step is skipped if the output is going to some other destination. - */ - if( eDest==SRT_Callback ){ - generateColumnNames(pParse, pTabList, pEList); - } - /* Generate code for all sub-queries in the FROM clause */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) @@ -3217,6 +3289,14 @@ int sqlite3Select( ** successful coding of the SELECT. */ select_end: + + /* Identify column names if we will be using them in a callback. This + ** step is skipped if the output is going to some other destination. + */ + if( rc==SQLITE_OK && eDest==SRT_Callback ){ + generateColumnNames(pParse, pTabList, pEList); + } + sqliteFree(sAggInfo.aCol); sqliteFree(sAggInfo.aFunc); return rc; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 79d64f4ff4..762320f1a8 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.160 2006/02/09 22:13:42 drh Exp $ +** @(#) $Id: sqlite.h.in,v 1.161 2006/02/10 02:27:43 danielk1977 Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -725,6 +725,27 @@ int sqlite3_column_count(sqlite3_stmt *pStmt); const char *sqlite3_column_name(sqlite3_stmt*,int); const void *sqlite3_column_name16(sqlite3_stmt*,int); +/* +** The first parameter to the following calls is a compiled SQL statement. +** These functions return information about the Nth column returned by +** the statement, where N is the second function argument. +** +** If the Nth column returned by the statement is not a column value, +** then all of the functions return NULL. Otherwise, the return the +** name of the attached database, table and column that the expression +** extracts a value from. +** +** As with all other SQLite APIs, those postfixed with "16" return UTF-16 +** encoded strings, the other functions return UTF-8. The memory containing +** the returned strings is valid until the statement handle is finalized(). +*/ +const char *sqlite3_column_database_name(sqlite3_stmt*,int); +const void *sqlite3_column_database_name16(sqlite3_stmt*,int); +const char *sqlite3_column_table_name(sqlite3_stmt*,int); +const void *sqlite3_column_table_name16(sqlite3_stmt*,int); +const char *sqlite3_column_origin_name(sqlite3_stmt*,int); +const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); + /* ** The first parameter is a compiled SQL statement. If this statement ** is a SELECT statement, the Nth column of the returned result set @@ -737,7 +758,7 @@ const void *sqlite3_column_name16(sqlite3_stmt*,int); ** ** And the following statement compiled: ** -** SELECT c1 + 1, 0 FROM t1; +** SELECT c1 + 1, c1 FROM t1; ** ** Then this routine would return the string "VARIANT" for the second ** result column (i==1), and a NULL pointer for the first result column @@ -757,7 +778,7 @@ const char *sqlite3_column_decltype(sqlite3_stmt *, int i); ** ** And the following statement compiled: ** -** SELECT c1 + 1, 0 FROM t1; +** SELECT c1 + 1, c1 FROM t1; ** ** Then this routine would return the string "INTEGER" for the second ** result column (i==1), and a NULL pointer for the first result column diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 427bc45ddb..914af2105a 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,7 +11,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.150 2006/01/23 13:00:38 drh Exp $ +** $Id: tclsqlite.c,v 1.151 2006/02/10 02:27:43 danielk1977 Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -1116,7 +1116,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ if( i+1!=nCol ){ char *zErr; zErr = malloc(200 + strlen(zFile)); - sprintf(zErr,"Error: %s line %d: expected %d columns of data but found %d", + sprintf(zErr, + "Error: %s line %d: expected %d columns of data but found %d", zFile, lineno, nCol, i+1); Tcl_AppendResult(interp, zErr, 0); free(zErr); diff --git a/src/test1.c b/src/test1.c index f8510cc23f..0ee8dadf6e 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.204 2006/02/09 13:43:29 danielk1977 Exp $ +** $Id: test1.c,v 1.205 2006/02/10 02:27:43 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -3571,11 +3571,19 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_column_name", test_stmt_utf8, sqlite3_column_name }, { "sqlite3_column_int", test_stmt_int, sqlite3_column_int }, { "sqlite3_column_bytes", test_stmt_int, sqlite3_column_bytes }, +{ "sqlite3_column_database_name", test_stmt_utf8, sqlite3_column_database_name}, +{ "sqlite3_column_table_name", test_stmt_utf8, sqlite3_column_table_name}, +{ "sqlite3_column_origin_name", test_stmt_utf8, sqlite3_column_origin_name}, + #ifndef SQLITE_OMIT_UTF16 { "sqlite3_column_bytes16", test_stmt_int, sqlite3_column_bytes16 }, { "sqlite3_column_text16", test_stmt_utf16, sqlite3_column_text16 }, { "sqlite3_column_decltype16", test_stmt_utf16, sqlite3_column_decltype16}, { "sqlite3_column_name16", test_stmt_utf16, sqlite3_column_name16 }, +{"sqlite3_column_database_name16", + test_stmt_utf16, sqlite3_column_database_name16}, +{"sqlite3_column_table_name16", test_stmt_utf16, sqlite3_column_table_name16}, +{"sqlite3_column_origin_name16", test_stmt_utf16, sqlite3_column_origin_name16}, #endif { "sqlite3_global_recover", test_global_recover, 0 }, diff --git a/src/update.c b/src/update.c index 83084d7ed0..c506c82901 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.121 2006/01/18 16:51:36 danielk1977 Exp $ +** $Id: update.c,v 1.122 2006/02/10 02:27:43 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -494,7 +494,7 @@ void sqlite3Update( if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){ sqlite3VdbeAddOp(v, OP_Callback, 1, 0); sqlite3VdbeSetNumCols(v, 1); - sqlite3VdbeSetColName(v, 0, "rows updated", P3_STATIC); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC); } update_cleanup: diff --git a/src/vdbe.h b/src/vdbe.h index bef16fdb49..93f9dc61a0 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.99 2005/09/20 17:42:23 drh Exp $ +** $Id: vdbe.h,v 1.100 2006/02/10 02:27:44 danielk1977 Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -79,6 +79,17 @@ typedef struct VdbeOpList VdbeOpList; */ #define P3_KEYINFO_HANDOFF (-9) +/* +** The Vdbe.aColName array contains 5n Mem structures, where n is the +** number of columns of data returned by the statement. +*/ +#define COLNAME_NAME 0 +#define COLNAME_DECLTYPE 1 +#define COLNAME_DATABASE 2 +#define COLNAME_TABLE 3 +#define COLNAME_COLUMN 4 +#define COLNAME_N 5 /* Number of COLNAME_xxx symbols */ + /* ** The following macro converts a relative address in the p2 field ** of a VdbeOp structure into a negative number so that @@ -117,7 +128,7 @@ void sqlite3VdbeTrace(Vdbe*,FILE*); int sqlite3VdbeReset(Vdbe*); int sqliteVdbeSetVariables(Vdbe*,int,const char**); void sqlite3VdbeSetNumCols(Vdbe*,int); -int sqlite3VdbeSetColName(Vdbe*, int, const char *, int); +int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int); void sqlite3VdbeCountChanges(Vdbe*); sqlite3 *sqlite3VdbeDb(Vdbe*); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 497f6c0095..e2866975a7 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -521,11 +521,13 @@ static const void *columnName( ** statement pStmt. */ const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){ - return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 0); + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME); } #ifndef SQLITE_OMIT_UTF16 const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ - return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 0); + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME); } #endif @@ -534,26 +536,30 @@ const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ ** of the result set of SQL statement pStmt. */ const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){ - return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 1); + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE); } #ifndef SQLITE_OMIT_UTF16 const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ - return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 1); + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE); } #endif /* SQLITE_OMIT_UTF16 */ -#if !defined(SQLITE_OMIT_ORIGIN_NAMES) && 0 +#if !defined(SQLITE_OMIT_ORIGIN_NAMES) /* ** Return the name of the database from which a result column derives. ** NULL is returned if the result column is an expression or constant or ** anything else which is not an unabiguous reference to a database column. */ const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){ - return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 2); + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE); } #ifndef SQLITE_OMIT_UTF16 const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){ - return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 2); + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE); } #endif /* SQLITE_OMIT_UTF16 */ @@ -563,11 +569,13 @@ const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){ ** anything else which is not an unabiguous reference to a database column. */ const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){ - return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 3); + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE); } #ifndef SQLITE_OMIT_UTF16 const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ - return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 3); + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE); } #endif /* SQLITE_OMIT_UTF16 */ @@ -577,11 +585,13 @@ const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ ** anything else which is not an unabiguous reference to a database column. */ const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){ - return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, 4); + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN); } #ifndef SQLITE_OMIT_UTF16 const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){ - return columnName(pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, 4); + return columnName( + pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN); } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_OMIT_ORIGIN_NAMES */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 04f9c9513f..33d2fbdcea 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -871,9 +871,9 @@ static void Cleanup(Vdbe *p){ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ Mem *pColName; int n; - releaseMemArray(p->aColName, p->nResColumn*2); + releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); sqliteFree(p->aColName); - n = nResColumn*2; + n = nResColumn*COLNAME_N; p->nResColumn = nResColumn; p->aColName = pColName = (Mem*)sqliteMalloc( sizeof(Mem)*n ); if( p->aColName==0 ) return; @@ -893,13 +893,14 @@ void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){ ** the string is freed using sqliteFree() when the vdbe is finished with ** it. Otherwise, N bytes of zName are copied. */ -int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){ +int sqlite3VdbeSetColName(Vdbe *p, int idx, int var, const char *zName, int N){ int rc; Mem *pColName; - assert( idx<(2*p->nResColumn) ); + assert( idxnResColumn ); + assert( varaColName!=0 ); - pColName = &(p->aColName[idx]); + pColName = &(p->aColName[idx+var*p->nResColumn]); if( N==P3_DYNAMIC || N==P3_STATIC ){ rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC); }else{ @@ -1481,7 +1482,7 @@ void sqlite3VdbeDelete(Vdbe *p){ releaseMemArray(p->aVar, p->nVar); sqliteFree(p->aLabel); sqliteFree(p->aStack); - releaseMemArray(p->aColName, p->nResColumn*2); + releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); sqliteFree(p->aColName); p->magic = VDBE_MAGIC_DEAD; sqliteFree(p); diff --git a/test/capi2.test b/test/capi2.test index 3d52d0b6e5..9fdd3617ed 100644 --- a/test/capi2.test +++ b/test/capi2.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script testing the callback-free C/C++ API. # -# $Id: capi2.test,v 1.27 2006/01/03 00:33:50 drh Exp $ +# $Id: capi2.test,v 1.28 2006/02/10 02:27:47 danielk1977 Exp $ # set testdir [file dirname $argv0] @@ -638,6 +638,8 @@ do_test capi2-9.1 { sqlite3_finalize $VM1 } {SQLITE_OK} +# Test that passing a NULL pointer to sqlite3_finalize() or sqlite3_reset +# does not cause an error. do_test capi2-10.1 { sqlite3_finalize 0 } {SQLITE_OK} @@ -645,6 +647,81 @@ do_test capi2-10.2 { sqlite3_reset 0 } {SQLITE_OK} +#--------------------------------------------------------------------------- +# The following tests - capi2-11.* - test the "column origin" APIs. +# +# sqlite3_column_origin_name() +# sqlite3_column_database_name() +# sqlite3_column_table_name() +# + +# This proc uses the database handle $::DB to compile the SQL statement passed +# as a parameter. The return value of this procedure is a list with one +# element for each column returned by the compiled statement. Each element of +# this list is itself a list of length three, consisting of the origin +# database, table and column for the corresponding returned column. +proc check_origins {sql} { + set ret [list] + set ::STMT [sqlite3_prepare $::DB $sql -1 dummy] + for {set i 0} {$i < [sqlite3_column_count $::STMT]} {incr i} { + lappend ret [list \ + [sqlite3_column_database_name $::STMT $i] \ + [sqlite3_column_table_name $::STMT $i] \ + [sqlite3_column_origin_name $::STMT $i] \ + ] + } + sqlite3_finalize $::STMT + return $ret +} +do_test capi2-11.1 { + execsql { + CREATE TABLE tab1(col1, col2); + } +} {} +do_test capi2-11.2 { + check_origins {SELECT col2, col1 FROM tab1} +} [list {main tab1 col2} {main tab1 col1}] +do_test capi2-11.3 { + check_origins {SELECT col2 AS hello, col1 AS world FROM tab1} +} [list {main tab1 col2} {main tab1 col1}] +do_test capi2-11.4 { + check_origins {SELECT b, a FROM (SELECT col1 AS a, col2 AS b FROM tab1)} +} [list {main tab1 col2} {main tab1 col1}] +do_test capi2-11.5 { + check_origins {SELECT (SELECT col2 FROM tab1), (SELECT col1 FROM tab1)} +} [list {main tab1 col2} {main tab1 col1}] +do_test capi2-11.6 { + check_origins {SELECT (SELECT col2), (SELECT col1) FROM tab1} +} [list {main tab1 col2} {main tab1 col1}] +do_test capi2-11.7 { + check_origins {SELECT * FROM tab1} +} [list {main tab1 col1} {main tab1 col2}] +do_test capi2-11.8 { + check_origins {SELECT * FROM (SELECT * FROM tab1)} +} [list {main tab1 col1} {main tab1 col2}] + +do_test capi2-12.1 { + execsql { + CREATE VIEW view1 AS SELECT * FROM tab1; + } +} {} +do_test capi2-12.2 { +breakpoint + check_origins {SELECT col2, col1 FROM view1} +} [list {main tab1 col2} {main tab1 col1}] +do_test capi2-12.3 { + check_origins {SELECT col2 AS hello, col1 AS world FROM view1} +} [list {main tab1 col2} {main tab1 col1}] +do_test capi2-12.4 { + check_origins {SELECT b, a FROM (SELECT col1 AS a, col2 AS b FROM view1)} +} [list {main tab1 col2} {main tab1 col1}] +do_test capi2-12.5 { + check_origins {SELECT (SELECT col2 FROM view1), (SELECT col1 FROM view1)} +} [list {main tab1 col2} {main tab1 col1}] +do_test capi2-12.6 { + check_origins {SELECT (SELECT col2), (SELECT col1) FROM view1} +} [list {main tab1 col2} {main tab1 col1}] + db2 close finish_test diff --git a/test/capi3.test b/test/capi3.test index 21542e5884..3d6fe1c571 100644 --- a/test/capi3.test +++ b/test/capi3.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script testing the callback-free C/C++ API. # -# $Id: capi3.test,v 1.41 2006/01/30 22:35:44 drh Exp $ +# $Id: capi3.test,v 1.42 2006/02/10 02:27:47 danielk1977 Exp $ # set testdir [file dirname $argv0] @@ -286,9 +286,94 @@ proc check_header {STMT test names decltypes} { [sqlite3_column_decltype16 $STMT $numcols] } {{} {} {} {} {} {} {} {}} } - } +# This proc is used to test the following API calls: +# +# sqlite3_column_origin_name +# sqlite3_column_origin_name16 +# sqlite3_column_table_name +# sqlite3_column_table_name16 +# sqlite3_column_database_name +# sqlite3_column_database_name16 +# +# $STMT is a compiled SQL statement. $test is a prefix +# to use for test names within this proc. $names is a list +# of the column names that should be returned by $STMT. +# $decltypes is a list of column declaration types for $STMT. +# +# Example: +# +# set STMT [sqlite3_prepare "SELECT 1, 2, 2;" -1 DUMMY] +# check_header test1.1 {1 2 3} {"" "" ""} +# +proc check_origin_header {STMT test dbs tables cols} { + # Use the return value of sqlite3_column_count() to build + # a list of column indexes. i.e. If sqlite3_column_count + # is 3, build the list {0 1 2}. + set ::idxlist [list] + set ::numcols [sqlite3_column_count $STMT] + for {set i 0} {$i < $::numcols} {incr i} {lappend ::idxlist $i} + + # Database names in UTF-8 + do_test $test.8 { + set cnamelist [list] + foreach i $idxlist { + lappend cnamelist [sqlite3_column_database_name $STMT $i] + } + set cnamelist + } $dbs + + # Database names in UTF-16 + ifcapable {utf16} { + do_test $test.9 { + set cnamelist [list] + foreach i $idxlist { + lappend cnamelist [utf8 [sqlite3_column_database_name16 $STMT $i]] + } + set cnamelist + } $dbs + } + + # Table names in UTF-8 + do_test $test.10 { + set cnamelist [list] + foreach i $idxlist {lappend cnamelist [sqlite3_column_table_name $STMT $i]} + set cnamelist + } $tables + + # Table names in UTF-16 + ifcapable {utf16} { + do_test $test.11 { + set cnamelist [list] + foreach i $idxlist { + lappend cnamelist [utf8 [sqlite3_column_table_name16 $STMT $i]] + } + set cnamelist + } $tables + } + + # Origin names in UTF-8 + do_test $test.12 { + set cnamelist [list] + foreach i $idxlist { + lappend cnamelist [sqlite3_column_origin_name $STMT $i] + } + set cnamelist + } $cols + + # Origin declaration types in UTF-16 + ifcapable {utf16} { + do_test $test.13 { + set cnamelist [list] + foreach i $idxlist { + lappend cnamelist [utf8 [sqlite3_column_origin_name16 $STMT $i]] + } + set cnamelist + } $cols + } +} + # This proc is used to test the following APIs: # # sqlite3_data_count @@ -450,11 +535,13 @@ do_test capi3-5.0 { } 3 check_header $STMT capi3-5.1 {a b c} {VARINT BLOB VARCHAR(16)} +check_origin_header $STMT capi3-5.1 {main main main} {t1 t1 t1} {a b c} do_test capi3-5.2 { sqlite3_step $STMT } SQLITE_ROW check_header $STMT capi3-5.3 {a b c} {VARINT BLOB VARCHAR(16)} +check_origin_header $STMT capi3-5.3 {main main main} {t1 t1 t1} {a b c} check_data $STMT capi3-5.4 {INTEGER INTEGER TEXT} {1 2 3} {1.0 2.0 3.0} {1 2 3} do_test capi3-5.5 { @@ -462,6 +549,7 @@ do_test capi3-5.5 { } SQLITE_ROW check_header $STMT capi3-5.6 {a b c} {VARINT BLOB VARCHAR(16)} +check_origin_header $STMT capi3-5.6 {main main main} {t1 t1 t1} {a b c} check_data $STMT capi3-5.7 {TEXT TEXT NULL} {0 0 0} {0.0 0.0 0.0} {one two {}} do_test capi3-5.8 { @@ -469,6 +557,7 @@ do_test capi3-5.8 { } SQLITE_ROW check_header $STMT capi3-5.9 {a b c} {VARINT BLOB VARCHAR(16)} +check_origin_header $STMT capi3-5.9 {main main main} {t1 t1 t1} {a b c} check_data $STMT capi3-5.10 {FLOAT FLOAT TEXT} {1 1 1} {1.2 1.3 1.4} {1.2 1.3 1.4} do_test capi3-5.11 {