diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 10 | ||||
-rw-r--r-- | src/select.c | 10 | ||||
-rw-r--r-- | src/shell.c | 10 | ||||
-rw-r--r-- | src/sqliteInt.h | 4 | ||||
-rw-r--r-- | src/table.c | 26 | ||||
-rw-r--r-- | src/tclsqlite.c | 59 | ||||
-rw-r--r-- | src/tokenize.c | 4 | ||||
-rw-r--r-- | src/vdbe.c | 55 | ||||
-rw-r--r-- | src/vdbe.h | 91 |
9 files changed, 165 insertions, 104 deletions
diff --git a/src/build.c b/src/build.c index fc45a3441..a87a74b44 100644 --- a/src/build.c +++ b/src/build.c @@ -25,7 +25,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.50 2001/10/15 00:44:36 drh Exp $ +** $Id: build.c,v 1.51 2001/10/19 16:44:57 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1449,6 +1449,14 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ } }else + if( sqliteStrICmp(zLeft, "empty_result_callbacks")==0 ){ + if( getBoolean(zRight) ){ + db->flags |= SQLITE_NullCallback; + }else{ + db->flags &= ~SQLITE_NullCallback; + } + }else + if( sqliteStrICmp(zLeft, "table_info")==0 ){ Table *pTab; Vdbe *v; diff --git a/src/select.c b/src/select.c index 49e8f02cd..c0e8961a6 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.41 2001/10/18 12:34:47 drh Exp $ +** $Id: select.c,v 1.42 2001/10/19 16:44:57 drh Exp $ */ #include "sqliteInt.h" @@ -994,5 +994,13 @@ int sqliteSelect( generateSortTail(v, pEList->nExpr); } pParse->nTab = base; + + + /* Issue a null callback if that is what the user wants. + */ + if( (pParse->db->flags & SQLITE_NullCallback)!=0 && eDest==SRT_Callback ){ + sqliteVdbeAddOp(v, OP_NullCallback, pEList->nExpr, 0); + } + return 0; } diff --git a/src/shell.c b/src/shell.c index 726dd9261..4eaab29a6 100644 --- a/src/shell.c +++ b/src/shell.c @@ -12,7 +12,7 @@ ** This file contains code to implement the "sqlite" command line ** utility for accessing SQLite databases. ** -** $Id: shell.c,v 1.36 2001/10/06 16:33:03 drh Exp $ +** $Id: shell.c,v 1.37 2001/10/19 16:44:57 drh Exp $ */ #include <stdlib.h> #include <string.h> @@ -244,6 +244,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ switch( p->mode ){ case MODE_Line: { int w = 5; + if( azArg==0 ) break; for(i=0; i<nArg; i++){ int len = strlen(azCol[i]); if( len>w ) w = len; @@ -266,7 +267,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ if( w<=0 ){ w = strlen(azCol[i] ? azCol[i] : ""); if( w<10 ) w = 10; - n = strlen(azArg[i] ? azArg[i] : ""); + n = strlen(azArg && azArg[i] ? azArg[i] : ""); if( w<n ) w = n; } if( i<ArraySize(p->actualWidth) ){ @@ -290,6 +291,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ } } } + if( azArg==0 ) break; for(i=0; i<nArg; i++){ int w; if( i<ArraySize(p->actualWidth) ){ @@ -309,6 +311,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator); } } + if( azArg==0 ) break; for(i=0; i<nArg; i++){ char *z = azArg[i]; if( z==0 ) z = ""; @@ -342,6 +345,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ } fprintf(p->out,"</TR>\n"); } + if( azArg==0 ) break; fprintf(p->out,"<TR>"); for(i=0; i<nArg; i++){ fprintf(p->out,"<TD>"); @@ -352,6 +356,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ break; } case MODE_Insert: { + if( azArg==0 ) break; fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable); for(i=0; i<nArg; i++){ char *zSep = i>0 ? ",": ""; @@ -365,6 +370,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ } } fprintf(p->out,");\n"); + break; } } return 0; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 92d01724b..8054316ec 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.63 2001/10/18 12:34:47 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.64 2001/10/19 16:44:57 drh Exp $ */ #include "sqlite.h" #include "hash.h" @@ -166,6 +166,8 @@ struct sqlite { #define SQLITE_CountRows 0x00000040 /* Count rows changed by INSERT, */ /* DELETE, or UPDATE and return */ /* the count using a callback. */ +#define SQLITE_NullCallback 0x00000080 /* Invoke the callback once if the */ + /* result set is empty */ /* ** Current file format version diff --git a/src/table.c b/src/table.c index e27c71460..39480dae1 100644 --- a/src/table.c +++ b/src/table.c @@ -47,7 +47,7 @@ static int sqlite_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ /* Make sure there is enough space in p->azResult to hold everything ** we need to remember from this invocation of the callback. */ - if( p->nRow==0 ){ + if( p->nRow==0 && argv!=0 ){ p->nColumn = nCol; need = nCol*2; }else{ @@ -83,20 +83,22 @@ static int sqlite_get_table_cb(void *pArg, int nCol, char **argv, char **colv){ /* Copy over the row data */ - for(i=0; i<nCol; i++){ - if( argv[i]==0 ){ - z = 0; - }else{ - z = malloc( strlen(argv[i])+1 ); - if( z==0 ){ - p->rc = SQLITE_NOMEM; - return 1; + if( argv!=0 ){ + for(i=0; i<nCol; i++){ + if( argv[i]==0 ){ + z = 0; + }else{ + z = malloc( strlen(argv[i])+1 ); + if( z==0 ){ + p->rc = SQLITE_NOMEM; + return 1; + } + strcpy(z, argv[i]); } - strcpy(z, argv[i]); + p->azResult[p->nData++] = z; } - p->azResult[p->nData++] = z; + p->nRow++; } - p->nRow++; return 0; } diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 7893b73b5..19e7ddb27 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -11,7 +11,7 @@ ************************************************************************* ** A TCL Interface to SQLite ** -** $Id: tclsqlite.c,v 1.25 2001/10/18 12:34:47 drh Exp $ +** $Id: tclsqlite.c,v 1.26 2001/10/19 16:44:57 drh Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ @@ -72,42 +72,44 @@ static int DbEvalCallback( #ifdef UTF_TRANSLATION_NEEDED Tcl_DString dCol; #endif - if( cbData->zArray[0] ){ - if( cbData->once ){ - Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0); - for(i=0; i<nCol; i++){ - Tcl_SetVar2(cbData->interp, cbData->zArray, "*", azN[i], - TCL_LIST_ELEMENT|TCL_APPEND_VALUE); - } - } + if( azCol==0 || (cbData->once && cbData->zArray[0]) ){ + Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0); for(i=0; i<nCol; i++){ - char *z = azCol[i]; - if( z==0 ) z = ""; + Tcl_SetVar2(cbData->interp, cbData->zArray, "*", azN[i], + TCL_LIST_ELEMENT|TCL_APPEND_VALUE); + } + cbData->once = 0; + } + if( azCol!=0 ){ + if( cbData->zArray[0] ){ + for(i=0; i<nCol; i++){ + char *z = azCol[i]; + if( z==0 ) z = ""; #ifdef UTF_TRANSLATION_NEEDED - Tcl_DStringInit(&dCol); - Tcl_ExternalToUtfDString(NULL, z, -1, &dCol); - Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], - Tcl_DStringValue(&dCol), 0); - Tcl_DStringFree(&dCol); + Tcl_DStringInit(&dCol); + Tcl_ExternalToUtfDString(NULL, z, -1, &dCol); + Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], + Tcl_DStringValue(&dCol), 0); + Tcl_DStringFree(&dCol); #else - Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], z, 0); + Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], z, 0); #endif - } - }else{ - for(i=0; i<nCol; i++){ - char *z = azCol[i]; - if( z==0 ) z = ""; + } + }else{ + for(i=0; i<nCol; i++){ + char *z = azCol[i]; + if( z==0 ) z = ""; #ifdef UTF_TRANSLATION_NEEDED - Tcl_DStringInit(&dCol); - Tcl_ExternalToUtfDString(NULL, z, -1, &dCol); - Tcl_SetVar(cbData->interp, azN[i], Tcl_DStringValue(&dCol), 0); - Tcl_DStringFree(&dCol); + Tcl_DStringInit(&dCol); + Tcl_ExternalToUtfDString(NULL, z, -1, &dCol); + Tcl_SetVar(cbData->interp, azN[i], Tcl_DStringValue(&dCol), 0); + Tcl_DStringFree(&dCol); #else - Tcl_SetVar(cbData->interp, azN[i], z, 0); + Tcl_SetVar(cbData->interp, azN[i], z, 0); #endif + } } } - cbData->once = 0; rc = Tcl_EvalObj(cbData->interp, cbData->pCode); if( rc==TCL_CONTINUE ) rc = TCL_OK; cbData->tcl_rc = rc; @@ -128,6 +130,7 @@ static int DbEvalCallback2( ){ Tcl_Obj *pList = (Tcl_Obj*)clientData; int i; + if( azCol==0 ) return 0; for(i=0; i<nCol; i++){ Tcl_Obj *pElem; if( azCol[i] && *azCol[i] ){ diff --git a/src/tokenize.c b/src/tokenize.c index ba64ddb24..944766fbd 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -15,7 +15,7 @@ ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.28 2001/10/18 12:34:48 drh Exp $ +** $Id: tokenize.c,v 1.29 2001/10/19 16:44:57 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -331,7 +331,7 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){ break; } for(i=1; isIdChar[z[i]]; i++){} - *tokenType = sqliteKeywordCode(z, i); + *tokenType = sqliteKeywordCode((char*)z, i); return i; } } diff --git a/src/vdbe.c b/src/vdbe.c index c1cdebf7a..92a5cc69e 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -30,7 +30,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.86 2001/10/18 12:34:48 drh Exp $ +** $Id: vdbe.c,v 1.87 2001/10/19 16:44:57 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -202,6 +202,7 @@ struct Vdbe { int nSet; /* Number of sets allocated */ Set *aSet; /* An array of sets */ int nFetch; /* Number of OP_Fetch instructions executed */ + int nCallback; /* Number of callbacks invoked so far */ }; /* @@ -811,17 +812,17 @@ static char *zOpName[] = { 0, "AggGet", "SetInsert", "SetFound", "SetNotFound", "SetClear", "MakeRecord", "MakeKey", "MakeIdxKey", "Goto", "If", "Halt", "ColumnCount", - "ColumnName", "Callback", "Integer", "String", - "Null", "Pop", "Dup", "Pull", - "Add", "AddImm", "Subtract", "Multiply", - "Divide", "Remainder", "BitAnd", "BitOr", - "BitNot", "ShiftLeft", "ShiftRight", "AbsValue", - "Precision", "Min", "Max", "Like", - "Glob", "Eq", "Ne", "Lt", - "Le", "Gt", "Ge", "IsNull", - "NotNull", "Negative", "And", "Or", - "Not", "Concat", "Noop", "Strlen", - "Substr", + "ColumnName", "Callback", "NullCallback", "Integer", + "String", "Null", "Pop", "Dup", + "Pull", "Add", "AddImm", "Subtract", + "Multiply", "Divide", "Remainder", "BitAnd", + "BitOr", "BitNot", "ShiftLeft", "ShiftRight", + "AbsValue", "Precision", "Min", "Max", + "Like", "Glob", "Eq", "Ne", + "Lt", "Le", "Gt", "Ge", + "IsNull", "NotNull", "Negative", "And", + "Or", "Not", "Concat", "Noop", + "Strlen", "Substr", }; /* @@ -1194,6 +1195,7 @@ case OP_ColumnCount: { p->azColName = sqliteRealloc(p->azColName, (pOp->p1+1)*sizeof(char*)); if( p->azColName==0 ) goto no_mem; p->azColName[pOp->p1] = 0; + p->nCallback = 0; break; } @@ -1207,6 +1209,7 @@ case OP_ColumnCount: { */ case OP_ColumnName: { p->azColName[pOp->p1] = pOp->p3 ? pOp->p3 : ""; + p->nCallback = 0; break; } @@ -1231,11 +1234,38 @@ case OP_Callback: { if( xCallback(pArg, pOp->p1, &zStack[i], p->azColName)!=0 ){ rc = SQLITE_ABORT; } + p->nCallback++; } PopStack(p, pOp->p1); break; } +/* Opcode: NullCallback P1 * * +** +** Invoke the callback function once with the 2nd argument (the +** number of columns) equal to P1 and with the 4th argument (the +** names of the columns) set according to prior OP_ColumnName and +** OP_ColumnCount instructions. This is all like the regular +** OP_Callback or OP_SortCallback opcodes. But the 3rd argument +** which normally contains a pointer to an array of pointers to +** data is NULL. +** +** The callback is only invoked if there have been no prior calls +** to OP_Callback or OP_SortCallback. +** +** This opcode is used to report the number and names of columns +** in cases where the result set is empty. +*/ +case OP_NullCallback: { + if( xCallback!=0 && p->nCallback==0 ){ + if( xCallback(pArg, pOp->p1, 0, p->azColName)!=0 ){ + rc = SQLITE_ABORT; + } + p->nCallback++; + } + break; +} + /* Opcode: Concat P1 P2 P3 ** ** Look at the first P1 elements of the stack. Append them all @@ -3376,6 +3406,7 @@ case OP_SortCallback: { if( xCallback(pArg, pOp->p1, (char**)zStack[i], p->azColName) ){ rc = SQLITE_ABORT; } + p->nCallback++; } POPSTACK; break; diff --git a/src/vdbe.h b/src/vdbe.h index 4a60fb68e..7475a7eac 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.29 2001/10/13 02:59:09 drh Exp $ +** $Id: vdbe.h,v 1.30 2001/10/19 16:44:57 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -155,50 +155,51 @@ typedef struct VdbeOp VdbeOp; #define OP_ColumnCount 72 #define OP_ColumnName 73 #define OP_Callback 74 - -#define OP_Integer 75 -#define OP_String 76 -#define OP_Null 77 -#define OP_Pop 78 -#define OP_Dup 79 -#define OP_Pull 80 - -#define OP_Add 81 -#define OP_AddImm 82 -#define OP_Subtract 83 -#define OP_Multiply 84 -#define OP_Divide 85 -#define OP_Remainder 86 -#define OP_BitAnd 87 -#define OP_BitOr 88 -#define OP_BitNot 89 -#define OP_ShiftLeft 90 -#define OP_ShiftRight 91 -#define OP_AbsValue 92 -#define OP_Precision 93 -#define OP_Min 94 -#define OP_Max 95 -#define OP_Like 96 -#define OP_Glob 97 -#define OP_Eq 98 -#define OP_Ne 99 -#define OP_Lt 100 -#define OP_Le 101 -#define OP_Gt 102 -#define OP_Ge 103 -#define OP_IsNull 104 -#define OP_NotNull 105 -#define OP_Negative 106 -#define OP_And 107 -#define OP_Or 108 -#define OP_Not 109 -#define OP_Concat 110 -#define OP_Noop 111 - -#define OP_Strlen 112 -#define OP_Substr 113 - -#define OP_MAX 113 +#define OP_NullCallback 75 + +#define OP_Integer 76 +#define OP_String 77 +#define OP_Null 78 +#define OP_Pop 79 +#define OP_Dup 80 +#define OP_Pull 81 + +#define OP_Add 82 +#define OP_AddImm 83 +#define OP_Subtract 84 +#define OP_Multiply 85 +#define OP_Divide 86 +#define OP_Remainder 87 +#define OP_BitAnd 88 +#define OP_BitOr 89 +#define OP_BitNot 90 +#define OP_ShiftLeft 91 +#define OP_ShiftRight 92 +#define OP_AbsValue 93 +#define OP_Precision 94 +#define OP_Min 95 +#define OP_Max 96 +#define OP_Like 97 +#define OP_Glob 98 +#define OP_Eq 99 +#define OP_Ne 100 +#define OP_Lt 101 +#define OP_Le 102 +#define OP_Gt 103 +#define OP_Ge 104 +#define OP_IsNull 105 +#define OP_NotNull 106 +#define OP_Negative 107 +#define OP_And 108 +#define OP_Or 109 +#define OP_Not 110 +#define OP_Concat 111 +#define OP_Noop 112 + +#define OP_Strlen 113 +#define OP_Substr 114 + +#define OP_MAX 114 /* ** Prototypes for the VDBE interface. See comments on the implementation |