aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build.c10
-rw-r--r--src/select.c10
-rw-r--r--src/shell.c10
-rw-r--r--src/sqliteInt.h4
-rw-r--r--src/table.c26
-rw-r--r--src/tclsqlite.c59
-rw-r--r--src/tokenize.c4
-rw-r--r--src/vdbe.c55
-rw-r--r--src/vdbe.h91
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