mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Split the IdList structure into IdList and SrcList. SrcList is used to
represent a FROM clause and IdList is used for everything else. This change allows SrcList to grow to support outer joins without burdening the other uses of IdList. (CVS 584) FossilOrigin-Name: a167b71d8c27e870bc3079c6132e483bffc83298
This commit is contained in:
32
manifest
32
manifest
@ -1,5 +1,5 @@
|
|||||||
C Change\sthe\snames\sof\sthe\sPushList\sand\sPopList\sopcodes\sto\sListPush\sand\sListPop\nso\sthat\sthey\swill\sappear\stogether\swith\sthe\sother\sList\sopcodes\sin\sthe\ndocumentation.\s(CVS\s583)
|
C Split\sthe\sIdList\sstructure\sinto\sIdList\sand\sSrcList.\s\sSrcList\sis\sused\sto\nrepresent\sa\sFROM\sclause\sand\sIdList\sis\sused\sfor\severything\selse.\s\sThis\schange\nallows\sSrcList\sto\sgrow\sto\ssupport\souter\sjoins\swithout\sburdening\sthe\sother\nuses\sof\sIdList.\s(CVS\s584)
|
||||||
D 2002-05-23T22:07:03
|
D 2002-05-24T02:04:33
|
||||||
F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
|
F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
|
||||||
F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
|
F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
|
||||||
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
||||||
@ -20,28 +20,28 @@ F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
|
|||||||
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
|
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
|
||||||
F src/btree.c c01b404b9373ae1c0daf7d1f9211c72ead67638e
|
F src/btree.c c01b404b9373ae1c0daf7d1f9211c72ead67638e
|
||||||
F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
|
F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
|
||||||
F src/build.c d88ad651bedecba69510d87d734040730305c528
|
F src/build.c 48bb306676b77711919adc3578655e3ebf2ac8f0
|
||||||
F src/delete.c 1dba1dd7fb7a477b44178f4990c20fa673ceb5be
|
F src/delete.c a2b098cbbf518e6b641847e26de85827793bc523
|
||||||
F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
|
F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
|
||||||
F src/expr.c 535c2468cfa9a8d043c6bbe50488849943da237b
|
F src/expr.c 818a702ba93e444813b8935a7ab509f6e3352b49
|
||||||
F src/func.c a31dcba85bc2ecb9b752980289cf7e6cd0cafbce
|
F src/func.c a31dcba85bc2ecb9b752980289cf7e6cd0cafbce
|
||||||
F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
|
F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
|
||||||
F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
|
F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
|
||||||
F src/insert.c 5b6586bb5d8306280253829f42f5f98b1455e757
|
F src/insert.c bbbd803da8b125ec5a5f881f4d559887eb922c57
|
||||||
F src/main.c 6e53c49a390fabd5fecce9e3b128c61c85208000
|
F src/main.c 6e53c49a390fabd5fecce9e3b128c61c85208000
|
||||||
F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b
|
F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b
|
||||||
F src/os.c 5ab8b6b4590d0c1ab8e96c67996c170e4462e0fc
|
F src/os.c 5ab8b6b4590d0c1ab8e96c67996c170e4462e0fc
|
||||||
F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10
|
F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10
|
||||||
F src/pager.c ba5740104cc27b342cd43eebfdc44d60f64a3ded
|
F src/pager.c ba5740104cc27b342cd43eebfdc44d60f64a3ded
|
||||||
F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e
|
F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e
|
||||||
F src/parse.y 3f2f7334aa1460bf5b208f51b9e1f53747e552ff
|
F src/parse.y 8053fead169ad8345b5a2cfc39749b63995daffb
|
||||||
F src/printf.c d8032ee18b860c812eeff596c9bebfdacb7930fd
|
F src/printf.c d8032ee18b860c812eeff596c9bebfdacb7930fd
|
||||||
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
||||||
F src/select.c 1b623a7d826ec7c245bc542b665d61724da2a62d
|
F src/select.c c46f4e0784175f2a8ec9fde26b7b4f8090cab9cb
|
||||||
F src/shell.c 1d22fe870ee852cfb975fd000dbe3973713d0a15
|
F src/shell.c 1d22fe870ee852cfb975fd000dbe3973713d0a15
|
||||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||||
F src/sqlite.h.in 0038faa6d642de06b91143ee65a131bd831d020b
|
F src/sqlite.h.in 0038faa6d642de06b91143ee65a131bd831d020b
|
||||||
F src/sqliteInt.h 7ef986dab669bf334bd90aac0cb73f8ef3254ca4
|
F src/sqliteInt.h 02d9d16c3eea463ff9bcbd13426627cb79d6d190
|
||||||
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
|
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
|
||||||
F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1
|
F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1
|
||||||
F src/test1.c 09d95048b66ce6dcd2bae90f443589043d7d631e
|
F src/test1.c 09d95048b66ce6dcd2bae90f443589043d7d631e
|
||||||
@ -49,12 +49,12 @@ F src/test2.c 669cc22781c6461a273416ec1a7414d25c081730
|
|||||||
F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e
|
F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e
|
||||||
F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
|
F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
|
||||||
F src/tokenize.c 5892a8eb8f0063718f5bec1a1b24f4c6029eba9b
|
F src/tokenize.c 5892a8eb8f0063718f5bec1a1b24f4c6029eba9b
|
||||||
F src/trigger.c a7990d424af58d809501a393f72c12d4b039eb63
|
F src/trigger.c bf1a4f6653e482be0052bc9ade9261cf814c705b
|
||||||
F src/update.c 1f8f7fde797bd607fe0afb4f96a6ad83c9e8ab7b
|
F src/update.c f68375173bf5338cae3e97012708e10f206aedd9
|
||||||
F src/util.c 707c30f8c13cddace7c08556ac450c0b786660b3
|
F src/util.c 707c30f8c13cddace7c08556ac450c0b786660b3
|
||||||
F src/vdbe.c 6c2eae8a1d03f41aa51e40772aebf581cf62d5b8
|
F src/vdbe.c 46fd7cbefdb788195c978e5d2f480d86ea1416e5
|
||||||
F src/vdbe.h def669b9f2728589aabcb5db756429db02465c9a
|
F src/vdbe.h def669b9f2728589aabcb5db756429db02465c9a
|
||||||
F src/where.c 293985b6cf8391c3dcef9efcac4654884370513a
|
F src/where.c 1516eb1c06ca6d15cd5cf982ae974cf58e5431ed
|
||||||
F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1
|
F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1
|
||||||
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
|
||||||
F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1
|
F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1
|
||||||
@ -134,7 +134,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
|
|||||||
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
||||||
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
||||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||||
P 82b74a494ac7c751a13e67dcfa7fffb1b98ec808
|
P c53b0b9283c5c34def87d58b03fd979d03dc0890
|
||||||
R 3e1a04e4d6e0a4fb68b8a11229bc1cc1
|
R 95dc28a2322a37ee9ed8c63d2402b526
|
||||||
U drh
|
U drh
|
||||||
Z 8e8caac647d0d1fcfa3e14c75f0d3c35
|
Z 694384ea6b2e1a364fadbb314a03dd97
|
||||||
|
@ -1 +1 @@
|
|||||||
c53b0b9283c5c34def87d58b03fd979d03dc0890
|
a167b71d8c27e870bc3079c6132e483bffc83298
|
60
src/build.c
60
src/build.c
@ -25,7 +25,7 @@
|
|||||||
** ROLLBACK
|
** ROLLBACK
|
||||||
** PRAGMA
|
** PRAGMA
|
||||||
**
|
**
|
||||||
** $Id: build.c,v 1.93 2002/05/22 21:27:03 drh Exp $
|
** $Id: build.c,v 1.94 2002/05/24 02:04:33 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -1535,30 +1535,80 @@ IdList *sqliteIdListAppend(IdList *pList, Token *pToken){
|
|||||||
return pList;
|
return pList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Append a new table name to the given SrcList. Create a new SrcList if
|
||||||
|
** need be. A new entry is created in the SrcList even if pToken is NULL.
|
||||||
|
**
|
||||||
|
** A new SrcList is returned, or NULL if malloc() fails.
|
||||||
|
*/
|
||||||
|
SrcList *sqliteSrcListAppend(SrcList *pList, Token *pToken){
|
||||||
|
if( pList==0 ){
|
||||||
|
pList = sqliteMalloc( sizeof(IdList) );
|
||||||
|
if( pList==0 ) return 0;
|
||||||
|
}
|
||||||
|
if( (pList->nSrc & 7)==0 ){
|
||||||
|
struct SrcList_item *a;
|
||||||
|
a = sqliteRealloc(pList->a, (pList->nSrc+8)*sizeof(pList->a[0]) );
|
||||||
|
if( a==0 ){
|
||||||
|
sqliteSrcListDelete(pList);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pList->a = a;
|
||||||
|
}
|
||||||
|
memset(&pList->a[pList->nSrc], 0, sizeof(pList->a[0]));
|
||||||
|
if( pToken ){
|
||||||
|
char **pz = &pList->a[pList->nSrc].zName;
|
||||||
|
sqliteSetNString(pz, pToken->z, pToken->n, 0);
|
||||||
|
if( *pz==0 ){
|
||||||
|
sqliteSrcListDelete(pList);
|
||||||
|
return 0;
|
||||||
|
}else{
|
||||||
|
sqliteDequote(*pz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pList->nSrc++;
|
||||||
|
return pList;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Add an alias to the last identifier on the given identifier list.
|
** Add an alias to the last identifier on the given identifier list.
|
||||||
*/
|
*/
|
||||||
void sqliteIdListAddAlias(IdList *pList, Token *pToken){
|
void sqliteSrcListAddAlias(SrcList *pList, Token *pToken){
|
||||||
if( pList && pList->nId>0 ){
|
if( pList && pList->nSrc>0 ){
|
||||||
int i = pList->nId - 1;
|
int i = pList->nSrc - 1;
|
||||||
sqliteSetNString(&pList->a[i].zAlias, pToken->z, pToken->n, 0);
|
sqliteSetNString(&pList->a[i].zAlias, pToken->z, pToken->n, 0);
|
||||||
sqliteDequote(pList->a[i].zAlias);
|
sqliteDequote(pList->a[i].zAlias);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Delete an entire IdList.
|
** Delete an IdList.
|
||||||
*/
|
*/
|
||||||
void sqliteIdListDelete(IdList *pList){
|
void sqliteIdListDelete(IdList *pList){
|
||||||
int i;
|
int i;
|
||||||
if( pList==0 ) return;
|
if( pList==0 ) return;
|
||||||
for(i=0; i<pList->nId; i++){
|
for(i=0; i<pList->nId; i++){
|
||||||
sqliteFree(pList->a[i].zName);
|
sqliteFree(pList->a[i].zName);
|
||||||
|
}
|
||||||
|
sqliteFree(pList->a);
|
||||||
|
sqliteFree(pList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Delete an entire SrcList including all its substructure.
|
||||||
|
*/
|
||||||
|
void sqliteSrcListDelete(SrcList *pList){
|
||||||
|
int i;
|
||||||
|
if( pList==0 ) return;
|
||||||
|
for(i=0; i<pList->nSrc; i++){
|
||||||
|
sqliteFree(pList->a[i].zName);
|
||||||
sqliteFree(pList->a[i].zAlias);
|
sqliteFree(pList->a[i].zAlias);
|
||||||
if( pList->a[i].pTab && pList->a[i].pTab->isTransient ){
|
if( pList->a[i].pTab && pList->a[i].pTab->isTransient ){
|
||||||
sqliteDeleteTable(0, pList->a[i].pTab);
|
sqliteDeleteTable(0, pList->a[i].pTab);
|
||||||
}
|
}
|
||||||
sqliteSelectDelete(pList->a[i].pSelect);
|
sqliteSelectDelete(pList->a[i].pSelect);
|
||||||
|
sqliteExprDelete(pList->a[i].pOn);
|
||||||
|
sqliteIdListDelete(pList->a[i].pUsing);
|
||||||
}
|
}
|
||||||
sqliteFree(pList->a);
|
sqliteFree(pList->a);
|
||||||
sqliteFree(pList);
|
sqliteFree(pList);
|
||||||
|
30
src/delete.c
30
src/delete.c
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle DELETE FROM statements.
|
** to handle DELETE FROM statements.
|
||||||
**
|
**
|
||||||
** $Id: delete.c,v 1.35 2002/05/23 12:50:18 drh Exp $
|
** $Id: delete.c,v 1.36 2002/05/24 02:04:33 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -43,22 +43,22 @@ Table *sqliteTableNameToTable(Parse *pParse, const char *zTab){
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Given a table name, check to make sure the table exists, is writable
|
** Given a table name, check to make sure the table exists, is writable
|
||||||
** and is not a view. If everything is OK, construct an IdList holding
|
** and is not a view. If everything is OK, construct an SrcList holding
|
||||||
** the table and return a pointer to the IdList. The calling function
|
** the table and return a pointer to the SrcList. The calling function
|
||||||
** is responsible for freeing the IdList when it has finished with it.
|
** is responsible for freeing the SrcList when it has finished with it.
|
||||||
** If there is an error, leave a message on pParse->zErrMsg and return
|
** If there is an error, leave a message on pParse->zErrMsg and return
|
||||||
** NULL.
|
** NULL.
|
||||||
*/
|
*/
|
||||||
IdList *sqliteTableTokenToIdList(Parse *pParse, Token *pTableName){
|
SrcList *sqliteTableTokenToSrcList(Parse *pParse, Token *pTableName){
|
||||||
Table *pTab;
|
Table *pTab;
|
||||||
IdList *pTabList;
|
SrcList *pTabList;
|
||||||
|
|
||||||
pTabList = sqliteIdListAppend(0, pTableName);
|
pTabList = sqliteSrcListAppend(0, pTableName);
|
||||||
if( pTabList==0 ) return 0;
|
if( pTabList==0 ) return 0;
|
||||||
assert( pTabList->nId==1 );
|
assert( pTabList->nSrc==1 );
|
||||||
pTab = sqliteTableNameToTable(pParse, pTabList->a[0].zName);
|
pTab = sqliteTableNameToTable(pParse, pTabList->a[0].zName);
|
||||||
if( pTab==0 ){
|
if( pTab==0 ){
|
||||||
sqliteIdListDelete(pTabList);
|
sqliteSrcListDelete(pTabList);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pTabList->a[0].pTab = pTab;
|
pTabList->a[0].pTab = pTab;
|
||||||
@ -76,7 +76,7 @@ void sqliteDeleteFrom(
|
|||||||
Vdbe *v; /* The virtual database engine */
|
Vdbe *v; /* The virtual database engine */
|
||||||
Table *pTab; /* The table from which records will be deleted */
|
Table *pTab; /* The table from which records will be deleted */
|
||||||
char *zTab; /* Name of the table from which we are deleting */
|
char *zTab; /* Name of the table from which we are deleting */
|
||||||
IdList *pTabList; /* An ID list holding pTab and nothing else */
|
SrcList *pTabList; /* A fake FROM clause holding just pTab */
|
||||||
int end, addr; /* A couple addresses of generated code */
|
int end, addr; /* A couple addresses of generated code */
|
||||||
int i; /* Loop counter */
|
int i; /* Loop counter */
|
||||||
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
||||||
@ -116,13 +116,13 @@ void sqliteDeleteFrom(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Locate the table which we want to delete. This table has to be
|
/* Locate the table which we want to delete. This table has to be
|
||||||
** put in an IdList structure because some of the subroutines we
|
** put in an SrcList structure because some of the subroutines we
|
||||||
** will be calling are designed to work with multiple tables and expect
|
** will be calling are designed to work with multiple tables and expect
|
||||||
** an IdList* parameter instead of just a Table* parameter.
|
** an SrcList* parameter instead of just a Table* parameter.
|
||||||
*/
|
*/
|
||||||
pTabList = sqliteTableTokenToIdList(pParse, pTableName);
|
pTabList = sqliteTableTokenToSrcList(pParse, pTableName);
|
||||||
if( pTabList==0 ) goto delete_from_cleanup;
|
if( pTabList==0 ) goto delete_from_cleanup;
|
||||||
assert( pTabList->nId==1 );
|
assert( pTabList->nSrc==1 );
|
||||||
pTab = pTabList->a[0].pTab;
|
pTab = pTabList->a[0].pTab;
|
||||||
assert( pTab->pSelect==0 ); /* This table is not a view */
|
assert( pTab->pSelect==0 ); /* This table is not a view */
|
||||||
|
|
||||||
@ -301,7 +301,7 @@ void sqliteDeleteFrom(
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete_from_cleanup:
|
delete_from_cleanup:
|
||||||
sqliteIdListDelete(pTabList);
|
sqliteSrcListDelete(pTabList);
|
||||||
sqliteExprDelete(pWhere);
|
sqliteExprDelete(pWhere);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
45
src/expr.c
45
src/expr.c
@ -12,7 +12,7 @@
|
|||||||
** This file contains routines used for analyzing expressions and
|
** This file contains routines used for analyzing expressions and
|
||||||
** for generating VDBE code that evaluates expressions in SQLite.
|
** for generating VDBE code that evaluates expressions in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: expr.c,v 1.62 2002/05/23 02:09:04 drh Exp $
|
** $Id: expr.c,v 1.63 2002/05/24 02:04:33 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -155,11 +155,11 @@ void sqliteSelectMoveStrings(Select *pSelect, int offset){
|
|||||||
** string space that is allocated separately from the expression tree
|
** string space that is allocated separately from the expression tree
|
||||||
** itself. These routines do NOT duplicate that string space.
|
** itself. These routines do NOT duplicate that string space.
|
||||||
**
|
**
|
||||||
** The expression list and ID list return by sqliteExprListDup() and
|
** The expression list, ID, and source lists return by sqliteExprListDup(),
|
||||||
** sqliteIdListDup() can not be further expanded by subsequent calls
|
** sqliteIdListDup(), and sqliteSrcListDup() can not be further expanded
|
||||||
** to sqliteExprListAppend() or sqliteIdListAppend().
|
** by subsequent calls to sqlite*ListAppend() routines.
|
||||||
**
|
**
|
||||||
** Any tables that the ID list might point to are not duplicated.
|
** Any tables that the SrcList might point to are not duplicated.
|
||||||
*/
|
*/
|
||||||
Expr *sqliteExprDup(Expr *p){
|
Expr *sqliteExprDup(Expr *p){
|
||||||
Expr *pNew;
|
Expr *pNew;
|
||||||
@ -196,6 +196,26 @@ ExprList *sqliteExprListDup(ExprList *p){
|
|||||||
}
|
}
|
||||||
return pNew;
|
return pNew;
|
||||||
}
|
}
|
||||||
|
SrcList *sqliteSrcListDup(SrcList *p){
|
||||||
|
SrcList *pNew;
|
||||||
|
int i;
|
||||||
|
if( p==0 ) return 0;
|
||||||
|
pNew = sqliteMalloc( sizeof(*pNew) );
|
||||||
|
if( pNew==0 ) return 0;
|
||||||
|
pNew->nSrc = p->nSrc;
|
||||||
|
pNew->a = sqliteMalloc( p->nSrc*sizeof(p->a[0]) );
|
||||||
|
if( pNew->a==0 ) return 0;
|
||||||
|
for(i=0; i<p->nSrc; i++){
|
||||||
|
pNew->a[i].zName = sqliteStrDup(p->a[i].zName);
|
||||||
|
pNew->a[i].zAlias = sqliteStrDup(p->a[i].zAlias);
|
||||||
|
pNew->a[i].jointype = p->a[i].jointype;
|
||||||
|
pNew->a[i].pTab = 0;
|
||||||
|
pNew->a[i].pSelect = sqliteSelectDup(p->a[i].pSelect);
|
||||||
|
pNew->a[i].pOn = sqliteExprDup(p->a[i].pOn);
|
||||||
|
pNew->a[i].pUsing = sqliteIdListDup(p->a[i].pUsing);
|
||||||
|
}
|
||||||
|
return pNew;
|
||||||
|
}
|
||||||
IdList *sqliteIdListDup(IdList *p){
|
IdList *sqliteIdListDup(IdList *p){
|
||||||
IdList *pNew;
|
IdList *pNew;
|
||||||
int i;
|
int i;
|
||||||
@ -207,10 +227,7 @@ IdList *sqliteIdListDup(IdList *p){
|
|||||||
if( pNew->a==0 ) return 0;
|
if( pNew->a==0 ) return 0;
|
||||||
for(i=0; i<p->nId; i++){
|
for(i=0; i<p->nId; i++){
|
||||||
pNew->a[i].zName = sqliteStrDup(p->a[i].zName);
|
pNew->a[i].zName = sqliteStrDup(p->a[i].zName);
|
||||||
pNew->a[i].zAlias = sqliteStrDup(p->a[i].zAlias);
|
|
||||||
pNew->a[i].idx = p->a[i].idx;
|
pNew->a[i].idx = p->a[i].idx;
|
||||||
pNew->a[i].pTab = 0;
|
|
||||||
pNew->a[i].pSelect = sqliteSelectDup(p->a[i].pSelect);
|
|
||||||
}
|
}
|
||||||
return pNew;
|
return pNew;
|
||||||
}
|
}
|
||||||
@ -221,7 +238,7 @@ Select *sqliteSelectDup(Select *p){
|
|||||||
if( pNew==0 ) return 0;
|
if( pNew==0 ) return 0;
|
||||||
pNew->isDistinct = p->isDistinct;
|
pNew->isDistinct = p->isDistinct;
|
||||||
pNew->pEList = sqliteExprListDup(p->pEList);
|
pNew->pEList = sqliteExprListDup(p->pEList);
|
||||||
pNew->pSrc = sqliteIdListDup(p->pSrc);
|
pNew->pSrc = sqliteSrcListDup(p->pSrc);
|
||||||
pNew->pWhere = sqliteExprDup(p->pWhere);
|
pNew->pWhere = sqliteExprDup(p->pWhere);
|
||||||
pNew->pGroupBy = sqliteExprListDup(p->pGroupBy);
|
pNew->pGroupBy = sqliteExprListDup(p->pGroupBy);
|
||||||
pNew->pHaving = sqliteExprDup(p->pHaving);
|
pNew->pHaving = sqliteExprDup(p->pHaving);
|
||||||
@ -362,12 +379,12 @@ static int sqliteIsRowid(const char *z){
|
|||||||
int sqliteExprResolveIds(
|
int sqliteExprResolveIds(
|
||||||
Parse *pParse, /* The parser context */
|
Parse *pParse, /* The parser context */
|
||||||
int base, /* VDBE cursor number for first entry in pTabList */
|
int base, /* VDBE cursor number for first entry in pTabList */
|
||||||
IdList *pTabList, /* List of tables used to resolve column names */
|
SrcList *pTabList, /* List of tables used to resolve column names */
|
||||||
ExprList *pEList, /* List of expressions used to resolve "AS" */
|
ExprList *pEList, /* List of expressions used to resolve "AS" */
|
||||||
Expr *pExpr /* The expression to be analyzed. */
|
Expr *pExpr /* The expression to be analyzed. */
|
||||||
){
|
){
|
||||||
if( pExpr==0 || pTabList==0 ) return 0;
|
if( pExpr==0 || pTabList==0 ) return 0;
|
||||||
assert( base+pTabList->nId<=pParse->nTab );
|
assert( base+pTabList->nSrc<=pParse->nTab );
|
||||||
switch( pExpr->op ){
|
switch( pExpr->op ){
|
||||||
/* Double-quoted strings (ex: "abc") are used as identifiers if
|
/* Double-quoted strings (ex: "abc") are used as identifiers if
|
||||||
** possible. Otherwise they remain as strings. Single-quoted
|
** possible. Otherwise they remain as strings. Single-quoted
|
||||||
@ -395,7 +412,7 @@ int sqliteExprResolveIds(
|
|||||||
z = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
|
z = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
|
||||||
sqliteDequote(z);
|
sqliteDequote(z);
|
||||||
if( z==0 ) return 1;
|
if( z==0 ) return 1;
|
||||||
for(i=0; i<pTabList->nId; i++){
|
for(i=0; i<pTabList->nSrc; i++){
|
||||||
int j;
|
int j;
|
||||||
Table *pTab = pTabList->a[i].pTab;
|
Table *pTab = pTabList->a[i].pTab;
|
||||||
if( pTab==0 ) continue;
|
if( pTab==0 ) continue;
|
||||||
@ -430,7 +447,7 @@ int sqliteExprResolveIds(
|
|||||||
if( cnt==0 && sqliteIsRowid(z) ){
|
if( cnt==0 && sqliteIsRowid(z) ){
|
||||||
pExpr->iColumn = -1;
|
pExpr->iColumn = -1;
|
||||||
pExpr->iTable = base;
|
pExpr->iTable = base;
|
||||||
cnt = 1 + (pTabList->nId>1);
|
cnt = 1 + (pTabList->nSrc>1);
|
||||||
pExpr->op = TK_COLUMN;
|
pExpr->op = TK_COLUMN;
|
||||||
}
|
}
|
||||||
sqliteFree(z);
|
sqliteFree(z);
|
||||||
@ -470,7 +487,7 @@ int sqliteExprResolveIds(
|
|||||||
sqliteDequote(zLeft);
|
sqliteDequote(zLeft);
|
||||||
sqliteDequote(zRight);
|
sqliteDequote(zRight);
|
||||||
pExpr->iTable = -1;
|
pExpr->iTable = -1;
|
||||||
for(i=0; i<pTabList->nId; i++){
|
for(i=0; i<pTabList->nSrc; i++){
|
||||||
int j;
|
int j;
|
||||||
char *zTab;
|
char *zTab;
|
||||||
Table *pTab = pTabList->a[i].pTab;
|
Table *pTab = pTabList->a[i].pTab;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle INSERT statements in SQLite.
|
** to handle INSERT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: insert.c,v 1.57 2002/05/21 12:56:43 drh Exp $
|
** $Id: insert.c,v 1.58 2002/05/24 02:04:33 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -117,12 +117,12 @@ void sqliteInsert(
|
|||||||
assert( pSelect->pEList );
|
assert( pSelect->pEList );
|
||||||
nColumn = pSelect->pEList->nExpr;
|
nColumn = pSelect->pEList->nExpr;
|
||||||
}else{
|
}else{
|
||||||
IdList dummy;
|
SrcList dummy;
|
||||||
assert( pList!=0 );
|
assert( pList!=0 );
|
||||||
srcTab = -1;
|
srcTab = -1;
|
||||||
assert( pList );
|
assert( pList );
|
||||||
nColumn = pList->nExpr;
|
nColumn = pList->nExpr;
|
||||||
dummy.nId = 0;
|
dummy.nSrc = 0;
|
||||||
for(i=0; i<nColumn; i++){
|
for(i=0; i<nColumn; i++){
|
||||||
if( sqliteExprResolveIds(pParse, 0, &dummy, 0, pList->a[i].pExpr) ){
|
if( sqliteExprResolveIds(pParse, 0, &dummy, 0, pList->a[i].pExpr) ){
|
||||||
goto insert_cleanup;
|
goto insert_cleanup;
|
||||||
|
61
src/parse.y
61
src/parse.y
@ -14,7 +14,7 @@
|
|||||||
** the parser. Lemon will also generate a header file containing
|
** the parser. Lemon will also generate a header file containing
|
||||||
** numeric codes for all of the tokens.
|
** numeric codes for all of the tokens.
|
||||||
**
|
**
|
||||||
** @(#) $Id: parse.y,v 1.67 2002/05/23 00:30:31 drh Exp $
|
** @(#) $Id: parse.y,v 1.68 2002/05/24 02:04:33 drh Exp $
|
||||||
*/
|
*/
|
||||||
%token_prefix TK_
|
%token_prefix TK_
|
||||||
%token_type {Token}
|
%token_type {Token}
|
||||||
@ -30,14 +30,24 @@
|
|||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A structure for holding two integers
|
** An instance of this structure holds information about the
|
||||||
|
** LIMIT clause of a SELECT statement.
|
||||||
*/
|
*/
|
||||||
struct twoint { int a,b; };
|
struct LimitVal {
|
||||||
|
int limit; /* The LIMIT value. -1 if there is no limit */
|
||||||
|
int offset; /* The OFFSET. 0 if there is none */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A structure for holding an integer and an IdList
|
** An instance of the following structure describes the event of a
|
||||||
|
** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT,
|
||||||
|
** TK_DELETE, or TK_INSTEAD. If the event is of the form
|
||||||
|
**
|
||||||
|
** UPDATE ON (a,b,c)
|
||||||
|
**
|
||||||
|
** Then the "b" IdList records the list "a,b,c".
|
||||||
*/
|
*/
|
||||||
struct int_idlist { int a; IdList * b; };
|
struct TrigEvent { int a; IdList * b; };
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are extra tokens used by the lexer but never seen by the
|
// These are extra tokens used by the lexer but never seen by the
|
||||||
@ -240,7 +250,7 @@ multiselect_op(A) ::= INTERSECT. {A = TK_INTERSECT;}
|
|||||||
multiselect_op(A) ::= EXCEPT. {A = TK_EXCEPT;}
|
multiselect_op(A) ::= EXCEPT. {A = TK_EXCEPT;}
|
||||||
oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
|
oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
|
||||||
groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
|
groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
|
||||||
A = sqliteSelectNew(W,X,Y,P,Q,Z,D,L.a,L.b);
|
A = sqliteSelectNew(W,X,Y,P,Q,Z,D,L.limit,L.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The "distinct" nonterminal is true (1) if the DISTINCT keyword is
|
// The "distinct" nonterminal is true (1) if the DISTINCT keyword is
|
||||||
@ -276,38 +286,38 @@ as ::= .
|
|||||||
as ::= AS.
|
as ::= AS.
|
||||||
|
|
||||||
|
|
||||||
%type seltablist {IdList*}
|
%type seltablist {SrcList*}
|
||||||
%destructor seltablist {sqliteIdListDelete($$);}
|
%destructor seltablist {sqliteSrcListDelete($$);}
|
||||||
%type stl_prefix {IdList*}
|
%type stl_prefix {SrcList*}
|
||||||
%destructor stl_prefix {sqliteIdListDelete($$);}
|
%destructor stl_prefix {sqliteSrcListDelete($$);}
|
||||||
%type from {IdList*}
|
%type from {SrcList*}
|
||||||
%destructor from {sqliteIdListDelete($$);}
|
%destructor from {sqliteSrcListDelete($$);}
|
||||||
|
|
||||||
from(A) ::= . {A = sqliteMalloc(sizeof(*A));}
|
from(A) ::= . {A = sqliteMalloc(sizeof(*A));}
|
||||||
from(A) ::= FROM seltablist(X). {A = X;}
|
from(A) ::= FROM seltablist(X). {A = X;}
|
||||||
stl_prefix(A) ::= seltablist(X) COMMA. {A = X;}
|
stl_prefix(A) ::= seltablist(X) COMMA. {A = X;}
|
||||||
stl_prefix(A) ::= . {A = 0;}
|
stl_prefix(A) ::= . {A = 0;}
|
||||||
seltablist(A) ::= stl_prefix(X) ids(Y). {A = sqliteIdListAppend(X,&Y);}
|
seltablist(A) ::= stl_prefix(X) ids(Y). {A = sqliteSrcListAppend(X,&Y);}
|
||||||
seltablist(A) ::= stl_prefix(X) ids(Y) as ids(Z). {
|
seltablist(A) ::= stl_prefix(X) ids(Y) as ids(Z). {
|
||||||
A = sqliteIdListAppend(X,&Y);
|
A = sqliteSrcListAppend(X,&Y);
|
||||||
sqliteIdListAddAlias(A,&Z);
|
sqliteSrcListAddAlias(A,&Z);
|
||||||
}
|
}
|
||||||
seltablist(A) ::= stl_prefix(X) LP select(S) RP. {
|
seltablist(A) ::= stl_prefix(X) LP select(S) RP. {
|
||||||
A = sqliteIdListAppend(X,0);
|
A = sqliteSrcListAppend(X,0);
|
||||||
A->a[A->nId-1].pSelect = S;
|
A->a[A->nSrc-1].pSelect = S;
|
||||||
if( S->pOrderBy ){
|
if( S->pOrderBy ){
|
||||||
sqliteExprListDelete(S->pOrderBy);
|
sqliteExprListDelete(S->pOrderBy);
|
||||||
S->pOrderBy = 0;
|
S->pOrderBy = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
seltablist(A) ::= stl_prefix(X) LP select(S) RP as ids(Z). {
|
seltablist(A) ::= stl_prefix(X) LP select(S) RP as ids(Z). {
|
||||||
A = sqliteIdListAppend(X,0);
|
A = sqliteSrcListAppend(X,0);
|
||||||
A->a[A->nId-1].pSelect = S;
|
A->a[A->nSrc-1].pSelect = S;
|
||||||
if( S->pOrderBy ){
|
if( S->pOrderBy ){
|
||||||
sqliteExprListDelete(S->pOrderBy);
|
sqliteExprListDelete(S->pOrderBy);
|
||||||
S->pOrderBy = 0;
|
S->pOrderBy = 0;
|
||||||
}
|
}
|
||||||
sqliteIdListAddAlias(A,&Z);
|
sqliteSrcListAddAlias(A,&Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
%type orderby_opt {ExprList*}
|
%type orderby_opt {ExprList*}
|
||||||
@ -345,11 +355,11 @@ groupby_opt(A) ::= GROUP BY exprlist(X). {A = X;}
|
|||||||
having_opt(A) ::= . {A = 0;}
|
having_opt(A) ::= . {A = 0;}
|
||||||
having_opt(A) ::= HAVING expr(X). {A = X;}
|
having_opt(A) ::= HAVING expr(X). {A = X;}
|
||||||
|
|
||||||
%type limit_opt {struct twoint}
|
%type limit_opt {struct LimitVal}
|
||||||
limit_opt(A) ::= . {A.a = -1; A.b = 0;}
|
limit_opt(A) ::= . {A.limit = -1; A.offset = 0;}
|
||||||
limit_opt(A) ::= LIMIT INTEGER(X). {A.a = atoi(X.z); A.b = 0;}
|
limit_opt(A) ::= LIMIT INTEGER(X). {A.limit = atoi(X.z); A.offset = 0;}
|
||||||
limit_opt(A) ::= LIMIT INTEGER(X) limit_sep INTEGER(Y).
|
limit_opt(A) ::= LIMIT INTEGER(X) limit_sep INTEGER(Y).
|
||||||
{A.a = atoi(X.z); A.b = atoi(Y.z);}
|
{A.limit = atoi(X.z); A.offset = atoi(Y.z);}
|
||||||
limit_sep ::= OFFSET.
|
limit_sep ::= OFFSET.
|
||||||
limit_sep ::= COMMA.
|
limit_sep ::= COMMA.
|
||||||
|
|
||||||
@ -655,7 +665,8 @@ trigger_time(A) ::= AFTER. { A = TK_AFTER; }
|
|||||||
trigger_time(A) ::= INSTEAD OF. { A = TK_INSTEAD;}
|
trigger_time(A) ::= INSTEAD OF. { A = TK_INSTEAD;}
|
||||||
trigger_time(A) ::= . { A = TK_BEFORE; }
|
trigger_time(A) ::= . { A = TK_BEFORE; }
|
||||||
|
|
||||||
%type trigger_event {struct int_idlist}
|
%type trigger_event {struct TrigEvent}
|
||||||
|
%destructor trigger_event {sqliteIdListDelete($$.b);}
|
||||||
trigger_event(A) ::= DELETE. { A.a = TK_DELETE; A.b = 0; }
|
trigger_event(A) ::= DELETE. { A.a = TK_DELETE; A.b = 0; }
|
||||||
trigger_event(A) ::= INSERT. { A.a = TK_INSERT; A.b = 0; }
|
trigger_event(A) ::= INSERT. { A.a = TK_INSERT; A.b = 0; }
|
||||||
trigger_event(A) ::= UPDATE. { A.a = TK_UPDATE; A.b = 0;}
|
trigger_event(A) ::= UPDATE. { A.a = TK_UPDATE; A.b = 0;}
|
||||||
|
44
src/select.c
44
src/select.c
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle SELECT statements in SQLite.
|
** to handle SELECT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: select.c,v 1.81 2002/05/08 11:54:15 drh Exp $
|
** $Id: select.c,v 1.82 2002/05/24 02:04:33 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
Select *sqliteSelectNew(
|
Select *sqliteSelectNew(
|
||||||
ExprList *pEList, /* which columns to include in the result */
|
ExprList *pEList, /* which columns to include in the result */
|
||||||
IdList *pSrc, /* the FROM clause -- which tables to scan */
|
SrcList *pSrc, /* the FROM clause -- which tables to scan */
|
||||||
Expr *pWhere, /* the WHERE clause */
|
Expr *pWhere, /* the WHERE clause */
|
||||||
ExprList *pGroupBy, /* the GROUP BY clause */
|
ExprList *pGroupBy, /* the GROUP BY clause */
|
||||||
Expr *pHaving, /* the HAVING clause */
|
Expr *pHaving, /* the HAVING clause */
|
||||||
@ -35,7 +35,7 @@ Select *sqliteSelectNew(
|
|||||||
pNew = sqliteMalloc( sizeof(*pNew) );
|
pNew = sqliteMalloc( sizeof(*pNew) );
|
||||||
if( pNew==0 ){
|
if( pNew==0 ){
|
||||||
sqliteExprListDelete(pEList);
|
sqliteExprListDelete(pEList);
|
||||||
sqliteIdListDelete(pSrc);
|
sqliteSrcListDelete(pSrc);
|
||||||
sqliteExprDelete(pWhere);
|
sqliteExprDelete(pWhere);
|
||||||
sqliteExprListDelete(pGroupBy);
|
sqliteExprListDelete(pGroupBy);
|
||||||
sqliteExprDelete(pHaving);
|
sqliteExprDelete(pHaving);
|
||||||
@ -61,7 +61,7 @@ Select *sqliteSelectNew(
|
|||||||
void sqliteSelectDelete(Select *p){
|
void sqliteSelectDelete(Select *p){
|
||||||
if( p==0 ) return;
|
if( p==0 ) return;
|
||||||
sqliteExprListDelete(p->pEList);
|
sqliteExprListDelete(p->pEList);
|
||||||
sqliteIdListDelete(p->pSrc);
|
sqliteSrcListDelete(p->pSrc);
|
||||||
sqliteExprDelete(p->pWhere);
|
sqliteExprDelete(p->pWhere);
|
||||||
sqliteExprListDelete(p->pGroupBy);
|
sqliteExprListDelete(p->pGroupBy);
|
||||||
sqliteExprDelete(p->pHaving);
|
sqliteExprDelete(p->pHaving);
|
||||||
@ -234,7 +234,7 @@ static void generateSortTail(Vdbe *v, int nColumn){
|
|||||||
static void generateColumnNames(
|
static void generateColumnNames(
|
||||||
Parse *pParse, /* Parser context */
|
Parse *pParse, /* Parser context */
|
||||||
int base, /* VDBE cursor corresponding to first entry in pTabList */
|
int base, /* VDBE cursor corresponding to first entry in pTabList */
|
||||||
IdList *pTabList, /* List of tables */
|
SrcList *pTabList, /* List of tables */
|
||||||
ExprList *pEList /* Expressions defining the result set */
|
ExprList *pEList /* Expressions defining the result set */
|
||||||
){
|
){
|
||||||
Vdbe *v = pParse->pVdbe;
|
Vdbe *v = pParse->pVdbe;
|
||||||
@ -265,7 +265,7 @@ static void generateColumnNames(
|
|||||||
if( iCol<0 ) iCol = pTab->iPKey;
|
if( iCol<0 ) iCol = pTab->iPKey;
|
||||||
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
|
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
|
||||||
zCol = iCol<0 ? "_ROWID_" : pTab->aCol[iCol].zName;
|
zCol = iCol<0 ? "_ROWID_" : pTab->aCol[iCol].zName;
|
||||||
if( pTabList->nId>1 || showFullNames ){
|
if( pTabList->nSrc>1 || showFullNames ){
|
||||||
char *zName = 0;
|
char *zName = 0;
|
||||||
char *zTab;
|
char *zTab;
|
||||||
|
|
||||||
@ -352,7 +352,7 @@ Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
|||||||
/*
|
/*
|
||||||
** For the given SELECT statement, do two things.
|
** For the given SELECT statement, do two things.
|
||||||
**
|
**
|
||||||
** (1) Fill in the pTabList->a[].pTab fields in the IdList that
|
** (1) Fill in the pTabList->a[].pTab fields in the SrcList that
|
||||||
** defines the set of tables that should be scanned.
|
** defines the set of tables that should be scanned.
|
||||||
**
|
**
|
||||||
** (2) Scan the list of columns in the result set (pEList) looking
|
** (2) Scan the list of columns in the result set (pEList) looking
|
||||||
@ -365,7 +365,7 @@ Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
|||||||
*/
|
*/
|
||||||
static int fillInColumnList(Parse *pParse, Select *p){
|
static int fillInColumnList(Parse *pParse, Select *p){
|
||||||
int i, j, k, rc;
|
int i, j, k, rc;
|
||||||
IdList *pTabList;
|
SrcList *pTabList;
|
||||||
ExprList *pEList;
|
ExprList *pEList;
|
||||||
Table *pTab;
|
Table *pTab;
|
||||||
|
|
||||||
@ -375,7 +375,7 @@ static int fillInColumnList(Parse *pParse, Select *p){
|
|||||||
|
|
||||||
/* Look up every table in the table list.
|
/* Look up every table in the table list.
|
||||||
*/
|
*/
|
||||||
for(i=0; i<pTabList->nId; i++){
|
for(i=0; i<pTabList->nSrc; i++){
|
||||||
if( pTabList->a[i].pTab ){
|
if( pTabList->a[i].pTab ){
|
||||||
/* This routine has run before! No need to continue */
|
/* This routine has run before! No need to continue */
|
||||||
return 0;
|
return 0;
|
||||||
@ -454,7 +454,7 @@ static int fillInColumnList(Parse *pParse, Select *p){
|
|||||||
}else{
|
}else{
|
||||||
pName = 0;
|
pName = 0;
|
||||||
}
|
}
|
||||||
for(i=0; i<pTabList->nId; i++){
|
for(i=0; i<pTabList->nSrc; i++){
|
||||||
Table *pTab = pTabList->a[i].pTab;
|
Table *pTab = pTabList->a[i].pTab;
|
||||||
char *zTabName = pTabList->a[i].zAlias;
|
char *zTabName = pTabList->a[i].zAlias;
|
||||||
if( zTabName==0 || zTabName[0]==0 ){
|
if( zTabName==0 || zTabName[0]==0 ){
|
||||||
@ -511,10 +511,10 @@ static int fillInColumnList(Parse *pParse, Select *p){
|
|||||||
*/
|
*/
|
||||||
void sqliteSelectUnbind(Select *p){
|
void sqliteSelectUnbind(Select *p){
|
||||||
int i;
|
int i;
|
||||||
IdList *pSrc = p->pSrc;
|
SrcList *pSrc = p->pSrc;
|
||||||
Table *pTab;
|
Table *pTab;
|
||||||
if( p==0 ) return;
|
if( p==0 ) return;
|
||||||
for(i=0; i<pSrc->nId; i++){
|
for(i=0; i<pSrc->nSrc; i++){
|
||||||
if( (pTab = pSrc->a[i].pTab)!=0 ){
|
if( (pTab = pSrc->a[i].pTab)!=0 ){
|
||||||
if( pTab->isTransient ){
|
if( pTab->isTransient ){
|
||||||
sqliteDeleteTable(0, pTab);
|
sqliteDeleteTable(0, pTab);
|
||||||
@ -932,8 +932,8 @@ substExprList(ExprList *pList, int iTable, ExprList *pEList, int iSub){
|
|||||||
*/
|
*/
|
||||||
int flattenSubquery(Select *p, int iFrom, int isAgg, int subqueryIsAgg){
|
int flattenSubquery(Select *p, int iFrom, int isAgg, int subqueryIsAgg){
|
||||||
Select *pSub; /* The inner query or "subquery" */
|
Select *pSub; /* The inner query or "subquery" */
|
||||||
IdList *pSrc; /* The FROM clause of the outer query */
|
SrcList *pSrc; /* The FROM clause of the outer query */
|
||||||
IdList *pSubSrc; /* The FROM clause of the subquery */
|
SrcList *pSubSrc; /* The FROM clause of the subquery */
|
||||||
ExprList *pList; /* The result set of the outer query */
|
ExprList *pList; /* The result set of the outer query */
|
||||||
int i;
|
int i;
|
||||||
int iParent, iSub;
|
int iParent, iSub;
|
||||||
@ -943,15 +943,15 @@ int flattenSubquery(Select *p, int iFrom, int isAgg, int subqueryIsAgg){
|
|||||||
*/
|
*/
|
||||||
if( p==0 ) return 0;
|
if( p==0 ) return 0;
|
||||||
pSrc = p->pSrc;
|
pSrc = p->pSrc;
|
||||||
assert( pSrc && iFrom>=0 && iFrom<pSrc->nId );
|
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
|
||||||
pSub = pSrc->a[iFrom].pSelect;
|
pSub = pSrc->a[iFrom].pSelect;
|
||||||
assert( pSub!=0 );
|
assert( pSub!=0 );
|
||||||
if( isAgg && subqueryIsAgg ) return 0;
|
if( isAgg && subqueryIsAgg ) return 0;
|
||||||
if( subqueryIsAgg && pSrc->nId>1 ) return 0;
|
if( subqueryIsAgg && pSrc->nSrc>1 ) return 0;
|
||||||
pSubSrc = pSub->pSrc;
|
pSubSrc = pSub->pSrc;
|
||||||
assert( pSubSrc );
|
assert( pSubSrc );
|
||||||
if( pSubSrc->nId!=1 ) return 0;
|
if( pSubSrc->nSrc!=1 ) return 0;
|
||||||
if( pSub->isDistinct && pSrc->nId>1 ) return 0;
|
if( pSub->isDistinct && pSrc->nSrc>1 ) return 0;
|
||||||
if( pSub->isDistinct && isAgg ) return 0;
|
if( pSub->isDistinct && isAgg ) return 0;
|
||||||
if( p->isDistinct && subqueryIsAgg ) return 0;
|
if( p->isDistinct && subqueryIsAgg ) return 0;
|
||||||
|
|
||||||
@ -1059,7 +1059,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
|
|||||||
** zero if it is not.
|
** zero if it is not.
|
||||||
*/
|
*/
|
||||||
if( p->pGroupBy || p->pHaving || p->pWhere ) return 0;
|
if( p->pGroupBy || p->pHaving || p->pWhere ) return 0;
|
||||||
if( p->pSrc->nId!=1 ) return 0;
|
if( p->pSrc->nSrc!=1 ) return 0;
|
||||||
if( p->pEList->nExpr!=1 ) return 0;
|
if( p->pEList->nExpr!=1 ) return 0;
|
||||||
pExpr = p->pEList->a[0].pExpr;
|
pExpr = p->pEList->a[0].pExpr;
|
||||||
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
|
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
|
||||||
@ -1184,7 +1184,7 @@ int sqliteSelect(
|
|||||||
Vdbe *v;
|
Vdbe *v;
|
||||||
int isAgg = 0; /* True for select lists like "count(*)" */
|
int isAgg = 0; /* True for select lists like "count(*)" */
|
||||||
ExprList *pEList; /* List of columns to extract. */
|
ExprList *pEList; /* List of columns to extract. */
|
||||||
IdList *pTabList; /* List of tables to select from */
|
SrcList *pTabList; /* List of tables to select from */
|
||||||
Expr *pWhere; /* The WHERE clause. May be NULL */
|
Expr *pWhere; /* The WHERE clause. May be NULL */
|
||||||
ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
|
ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
|
||||||
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
|
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
|
||||||
@ -1216,7 +1216,7 @@ int sqliteSelect(
|
|||||||
** FROM clause be consecutive.
|
** FROM clause be consecutive.
|
||||||
*/
|
*/
|
||||||
base = p->base = pParse->nTab;
|
base = p->base = pParse->nTab;
|
||||||
pParse->nTab += pTabList->nId;
|
pParse->nTab += pTabList->nSrc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Do not even attempt to generate any code if we have already seen
|
** Do not even attempt to generate any code if we have already seen
|
||||||
@ -1351,7 +1351,7 @@ int sqliteSelect(
|
|||||||
|
|
||||||
/* Generate code for all sub-queries in the FROM clause
|
/* Generate code for all sub-queries in the FROM clause
|
||||||
*/
|
*/
|
||||||
for(i=0; i<pTabList->nId; i++){
|
for(i=0; i<pTabList->nSrc; i++){
|
||||||
if( pTabList->a[i].pSelect==0 ) continue;
|
if( pTabList->a[i].pSelect==0 ) continue;
|
||||||
sqliteSelect(pParse, pTabList->a[i].pSelect, SRT_TempTable, base+i,
|
sqliteSelect(pParse, pTabList->a[i].pSelect, SRT_TempTable, base+i,
|
||||||
p, i, &isAgg);
|
p, i, &isAgg);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.112 2002/05/21 13:18:26 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.113 2002/05/24 02:04:33 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqlite.h"
|
#include "sqlite.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
@ -139,6 +139,7 @@ typedef struct ExprList ExprList;
|
|||||||
typedef struct Parse Parse;
|
typedef struct Parse Parse;
|
||||||
typedef struct Token Token;
|
typedef struct Token Token;
|
||||||
typedef struct IdList IdList;
|
typedef struct IdList IdList;
|
||||||
|
typedef struct SrcList SrcList;
|
||||||
typedef struct WhereInfo WhereInfo;
|
typedef struct WhereInfo WhereInfo;
|
||||||
typedef struct WhereLevel WhereLevel;
|
typedef struct WhereLevel WhereLevel;
|
||||||
typedef struct Select Select;
|
typedef struct Select Select;
|
||||||
@ -400,7 +401,7 @@ struct Expr {
|
|||||||
** name. An expr/name combination can be used in several ways, such
|
** name. An expr/name combination can be used in several ways, such
|
||||||
** as the list of "expr AS ID" fields following a "SELECT" or in the
|
** as the list of "expr AS ID" fields following a "SELECT" or in the
|
||||||
** list of "ID = expr" items in an UPDATE. A list of expressions can
|
** list of "ID = expr" items in an UPDATE. A list of expressions can
|
||||||
** also be used as the argument to a function, in which case the azName
|
** also be used as the argument to a function, in which case the a.zName
|
||||||
** field is not used.
|
** field is not used.
|
||||||
*/
|
*/
|
||||||
struct ExprList {
|
struct ExprList {
|
||||||
@ -415,16 +416,43 @@ struct ExprList {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A list of identifiers.
|
** An instance of this structure can hold a simple list of identifiers,
|
||||||
|
** such as the list "a,b,c" in the following statements:
|
||||||
|
**
|
||||||
|
** INSERT INTO t(a,b,c) VALUES ...;
|
||||||
|
** CREATE INDEX idx ON t(a,b,c);
|
||||||
|
** CREATE TRIGGER trig BEFORE UPDATE ON t(a,b,c) ...;
|
||||||
|
**
|
||||||
|
** The IdList.a.idx field is used when the IdList represents the list of
|
||||||
|
** column names after a table name in an INSERT statement. In the statement
|
||||||
|
**
|
||||||
|
** INSERT INTO t(a,b,c) ...
|
||||||
|
**
|
||||||
|
** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
|
||||||
*/
|
*/
|
||||||
struct IdList {
|
struct IdList {
|
||||||
int nId; /* Number of identifiers on the list */
|
int nId; /* Number of identifiers on the list */
|
||||||
struct IdList_item {
|
struct IdList_item {
|
||||||
char *zName; /* Text of the identifier. */
|
char *zName; /* Name of the identifier */
|
||||||
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
|
|
||||||
int idx; /* Index in some Table.aCol[] of a column named zName */
|
int idx; /* Index in some Table.aCol[] of a column named zName */
|
||||||
|
} *a;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following structure describes the FROM clause of a SELECT statement.
|
||||||
|
** Each table or subquery in the FROM clause is a separate element of
|
||||||
|
** the SrcList.a[] array.
|
||||||
|
*/
|
||||||
|
struct SrcList {
|
||||||
|
int nSrc; /* Number of tables or subqueries in the FROM clause */
|
||||||
|
struct SrcList_item {
|
||||||
|
char *zName; /* Name of the table */
|
||||||
|
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
|
||||||
Table *pTab; /* An SQL table corresponding to zName */
|
Table *pTab; /* An SQL table corresponding to zName */
|
||||||
Select *pSelect; /* A SELECT statement used in place of a table name */
|
Select *pSelect; /* A SELECT statement used in place of a table name */
|
||||||
|
int jointype; /* Type of join between this table and the next */
|
||||||
|
Expr *pOn; /* The ON clause of a join */
|
||||||
|
IdList *pUsing; /* The USING clause of a join */
|
||||||
} *a; /* One entry for each identifier on the list */
|
} *a; /* One entry for each identifier on the list */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -453,7 +481,7 @@ struct WhereLevel {
|
|||||||
*/
|
*/
|
||||||
struct WhereInfo {
|
struct WhereInfo {
|
||||||
Parse *pParse;
|
Parse *pParse;
|
||||||
IdList *pTabList; /* List of tables in the join */
|
SrcList *pTabList; /* List of tables in the join */
|
||||||
int iContinue; /* Jump here to continue with next record */
|
int iContinue; /* Jump here to continue with next record */
|
||||||
int iBreak; /* Jump here to break out of the loop */
|
int iBreak; /* Jump here to break out of the loop */
|
||||||
int base; /* Index of first Open opcode */
|
int base; /* Index of first Open opcode */
|
||||||
@ -478,7 +506,7 @@ struct WhereInfo {
|
|||||||
struct Select {
|
struct Select {
|
||||||
int isDistinct; /* True if the DISTINCT keyword is present */
|
int isDistinct; /* True if the DISTINCT keyword is present */
|
||||||
ExprList *pEList; /* The fields of the result */
|
ExprList *pEList; /* The fields of the result */
|
||||||
IdList *pSrc; /* The FROM clause */
|
SrcList *pSrc; /* The FROM clause */
|
||||||
Expr *pWhere; /* The WHERE clause */
|
Expr *pWhere; /* The WHERE clause */
|
||||||
ExprList *pGroupBy; /* The GROUP BY clause */
|
ExprList *pGroupBy; /* The GROUP BY clause */
|
||||||
Expr *pHaving; /* The HAVING clause */
|
Expr *pHaving; /* The HAVING clause */
|
||||||
@ -569,16 +597,17 @@ struct Parse {
|
|||||||
* 1. In the "trigHash" hash table (part of the sqlite* that represents the
|
* 1. In the "trigHash" hash table (part of the sqlite* that represents the
|
||||||
* database). This allows Trigger structures to be retrieved by name.
|
* database). This allows Trigger structures to be retrieved by name.
|
||||||
* 2. All triggers associated with a single table form a linked list, using the
|
* 2. All triggers associated with a single table form a linked list, using the
|
||||||
* pNext member of struct Trigger. A pointer to the first element of the linked
|
* pNext member of struct Trigger. A pointer to the first element of the
|
||||||
* list is stored as the "pTrigger" member of the associated struct Table.
|
* linked list is stored as the "pTrigger" member of the associated
|
||||||
|
* struct Table.
|
||||||
*
|
*
|
||||||
* The "strings" member of struct Trigger contains a pointer to the memory
|
* The "strings" member of struct Trigger contains a pointer to the memory
|
||||||
* referenced by the various Token structures referenced indirectly by the
|
* referenced by the various Token structures referenced indirectly by the
|
||||||
* "pWhen", "pColumns" and "step_list" members. (ie. the memory allocated for
|
* "pWhen", "pColumns" and "step_list" members. (ie. the memory allocated for
|
||||||
* use in conjunction with the sqliteExprMoveStrings() etc. interface).
|
* use in conjunction with the sqliteExprMoveStrings() etc. interface).
|
||||||
*
|
*
|
||||||
* The "step_list" member points to the first element of a linked list containing
|
* The "step_list" member points to the first element of a linked list
|
||||||
* the SQL statements specified as the trigger program.
|
* containing the SQL statements specified as the trigger program.
|
||||||
*
|
*
|
||||||
* When a trigger is initially created, the "isCommit" member is set to FALSE.
|
* When a trigger is initially created, the "isCommit" member is set to FALSE.
|
||||||
* When a transaction is rolled back, any Trigger structures with "isCommit" set
|
* When a transaction is rolled back, any Trigger structures with "isCommit" set
|
||||||
@ -587,8 +616,8 @@ struct Parse {
|
|||||||
* Trigger structures for which it is FALSE.
|
* Trigger structures for which it is FALSE.
|
||||||
*
|
*
|
||||||
* When a trigger is dropped, using the sqliteDropTrigger() interfaced, it is
|
* When a trigger is dropped, using the sqliteDropTrigger() interfaced, it is
|
||||||
* removed from the trigHash hash table and added to the trigDrop hash table. If
|
* removed from the trigHash hash table and added to the trigDrop hash table.
|
||||||
* the transaction is rolled back, the trigger is re-added into the trigHash
|
* If the transaction is rolled back, the trigger is re-added into the trigHash
|
||||||
* hash table (and hence the database schema). If the transaction is commited,
|
* hash table (and hence the database schema). If the transaction is commited,
|
||||||
* then the Trigger structure is deleted permanently.
|
* then the Trigger structure is deleted permanently.
|
||||||
*/
|
*/
|
||||||
@ -629,7 +658,8 @@ struct Trigger {
|
|||||||
* pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
|
* pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
|
||||||
* this stores values to be inserted. Otherwise NULL.
|
* this stores values to be inserted. Otherwise NULL.
|
||||||
* pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
|
* pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
|
||||||
* statement, then this stores the column-names to be inserted into.
|
* statement, then this stores the column-names to be
|
||||||
|
* inserted into.
|
||||||
*
|
*
|
||||||
* (op == TK_DELETE)
|
* (op == TK_DELETE)
|
||||||
* target -> A token holding the name of the table to delete from.
|
* target -> A token holding the name of the table to delete from.
|
||||||
@ -641,7 +671,8 @@ struct Trigger {
|
|||||||
* pWhere -> The WHERE clause of the UPDATE statement if one is specified.
|
* pWhere -> The WHERE clause of the UPDATE statement if one is specified.
|
||||||
* Otherwise NULL.
|
* Otherwise NULL.
|
||||||
* pExprList -> A list of the columns to update and the expressions to update
|
* pExprList -> A list of the columns to update and the expressions to update
|
||||||
* them to. See sqliteUpdate() documentation of "pChanges" argument.
|
* them to. See sqliteUpdate() documentation of "pChanges"
|
||||||
|
* argument.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct TriggerStep {
|
struct TriggerStep {
|
||||||
@ -755,20 +786,22 @@ void sqliteDropTable(Parse*, Token*, int);
|
|||||||
void sqliteDeleteTable(sqlite*, Table*);
|
void sqliteDeleteTable(sqlite*, Table*);
|
||||||
void sqliteInsert(Parse*, Token*, ExprList*, Select*, IdList*, int);
|
void sqliteInsert(Parse*, Token*, ExprList*, Select*, IdList*, int);
|
||||||
IdList *sqliteIdListAppend(IdList*, Token*);
|
IdList *sqliteIdListAppend(IdList*, Token*);
|
||||||
void sqliteIdListAddAlias(IdList*, Token*);
|
SrcList *sqliteSrcListAppend(SrcList*, Token*);
|
||||||
|
void sqliteSrcListAddAlias(SrcList*, Token*);
|
||||||
void sqliteIdListDelete(IdList*);
|
void sqliteIdListDelete(IdList*);
|
||||||
|
void sqliteSrcListDelete(SrcList*);
|
||||||
void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, int, Token*, Token*);
|
void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, int, Token*, Token*);
|
||||||
void sqliteDropIndex(Parse*, Token*);
|
void sqliteDropIndex(Parse*, Token*);
|
||||||
int sqliteSelect(Parse*, Select*, int, int, Select*, int, int*);
|
int sqliteSelect(Parse*, Select*, int, int, Select*, int, int*);
|
||||||
Select *sqliteSelectNew(ExprList*,IdList*,Expr*,ExprList*,Expr*,ExprList*,
|
Select *sqliteSelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*,
|
||||||
int,int,int);
|
int,int,int);
|
||||||
void sqliteSelectDelete(Select*);
|
void sqliteSelectDelete(Select*);
|
||||||
void sqliteSelectUnbind(Select*);
|
void sqliteSelectUnbind(Select*);
|
||||||
Table *sqliteTableNameToTable(Parse*, const char*);
|
Table *sqliteTableNameToTable(Parse*, const char*);
|
||||||
IdList *sqliteTableTokenToIdList(Parse*, Token*);
|
SrcList *sqliteTableTokenToSrcList(Parse*, Token*);
|
||||||
void sqliteDeleteFrom(Parse*, Token*, Expr*);
|
void sqliteDeleteFrom(Parse*, Token*, Expr*);
|
||||||
void sqliteUpdate(Parse*, Token*, ExprList*, Expr*, int);
|
void sqliteUpdate(Parse*, Token*, ExprList*, Expr*, int);
|
||||||
WhereInfo *sqliteWhereBegin(Parse*, int, IdList*, Expr*, int);
|
WhereInfo *sqliteWhereBegin(Parse*, int, SrcList*, Expr*, int);
|
||||||
void sqliteWhereEnd(WhereInfo*);
|
void sqliteWhereEnd(WhereInfo*);
|
||||||
void sqliteExprCode(Parse*, Expr*);
|
void sqliteExprCode(Parse*, Expr*);
|
||||||
void sqliteExprIfTrue(Parse*, Expr*, int);
|
void sqliteExprIfTrue(Parse*, Expr*, int);
|
||||||
@ -784,7 +817,7 @@ char *sqliteTableNameFromToken(Token*);
|
|||||||
int sqliteExprCheck(Parse*, Expr*, int, int*);
|
int sqliteExprCheck(Parse*, Expr*, int, int*);
|
||||||
int sqliteExprCompare(Expr*, Expr*);
|
int sqliteExprCompare(Expr*, Expr*);
|
||||||
int sqliteFuncId(Token*);
|
int sqliteFuncId(Token*);
|
||||||
int sqliteExprResolveIds(Parse*, int, IdList*, ExprList*, Expr*);
|
int sqliteExprResolveIds(Parse*, int, SrcList*, ExprList*, Expr*);
|
||||||
int sqliteExprAnalyzeAggregates(Parse*, Expr*);
|
int sqliteExprAnalyzeAggregates(Parse*, Expr*);
|
||||||
Vdbe *sqliteGetVdbe(Parse*);
|
Vdbe *sqliteGetVdbe(Parse*);
|
||||||
int sqliteRandomByte(void);
|
int sqliteRandomByte(void);
|
||||||
@ -805,6 +838,7 @@ void sqliteExprListMoveStrings(ExprList*, int);
|
|||||||
void sqliteSelectMoveStrings(Select*, int);
|
void sqliteSelectMoveStrings(Select*, int);
|
||||||
Expr *sqliteExprDup(Expr*);
|
Expr *sqliteExprDup(Expr*);
|
||||||
ExprList *sqliteExprListDup(ExprList*);
|
ExprList *sqliteExprListDup(ExprList*);
|
||||||
|
SrcList *sqliteSrcListDup(SrcList*);
|
||||||
IdList *sqliteIdListDup(IdList*);
|
IdList *sqliteIdListDup(IdList*);
|
||||||
Select *sqliteSelectDup(Select*);
|
Select *sqliteSelectDup(Select*);
|
||||||
FuncDef *sqliteFindFunction(sqlite*,const char*,int,int,int);
|
FuncDef *sqliteFindFunction(sqlite*,const char*,int,int,int);
|
||||||
|
@ -571,10 +571,10 @@ int sqliteCodeRowTrigger(
|
|||||||
|
|
||||||
if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){
|
if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){
|
||||||
int endTrigger;
|
int endTrigger;
|
||||||
IdList dummyTablist;
|
SrcList dummyTablist;
|
||||||
Expr * whenExpr;
|
Expr * whenExpr;
|
||||||
|
|
||||||
dummyTablist.nId = 0;
|
dummyTablist.nSrc = 0;
|
||||||
dummyTablist.a = 0;
|
dummyTablist.a = 0;
|
||||||
|
|
||||||
/* Push an entry on to the trigger stack */
|
/* Push an entry on to the trigger stack */
|
||||||
@ -645,7 +645,7 @@ void sqliteViewTriggers(
|
|||||||
|
|
||||||
theSelect.isDistinct = 0;
|
theSelect.isDistinct = 0;
|
||||||
theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0);
|
theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0);
|
||||||
theSelect.pSrc = sqliteIdListAppend(0, &tblNameToken);
|
theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken);
|
||||||
theSelect.pWhere = pWhere; pWhere = 0;
|
theSelect.pWhere = pWhere; pWhere = 0;
|
||||||
theSelect.pGroupBy = 0;
|
theSelect.pGroupBy = 0;
|
||||||
theSelect.pHaving = 0;
|
theSelect.pHaving = 0;
|
||||||
@ -750,7 +750,7 @@ trigger_cleanup:
|
|||||||
sqliteExprListDelete(pChanges);
|
sqliteExprListDelete(pChanges);
|
||||||
sqliteExprDelete(pWhere);
|
sqliteExprDelete(pWhere);
|
||||||
sqliteExprListDelete(theSelect.pEList);
|
sqliteExprListDelete(theSelect.pEList);
|
||||||
sqliteIdListDelete(theSelect.pSrc);
|
sqliteSrcListDelete(theSelect.pSrc);
|
||||||
sqliteExprDelete(theSelect.pWhere);
|
sqliteExprDelete(theSelect.pWhere);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
12
src/update.c
12
src/update.c
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle UPDATE statements.
|
** to handle UPDATE statements.
|
||||||
**
|
**
|
||||||
** $Id: update.c,v 1.42 2002/05/23 22:07:03 drh Exp $
|
** $Id: update.c,v 1.43 2002/05/24 02:04:34 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ void sqliteUpdate(
|
|||||||
){
|
){
|
||||||
int i, j; /* Loop counters */
|
int i, j; /* Loop counters */
|
||||||
Table *pTab; /* The table to be updated */
|
Table *pTab; /* The table to be updated */
|
||||||
IdList *pTabList = 0; /* List containing only pTab */
|
SrcList *pTabList = 0; /* Fake FROM clause containing only pTab */
|
||||||
int addr; /* VDBE instruction address of the start of the loop */
|
int addr; /* VDBE instruction address of the start of the loop */
|
||||||
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
WhereInfo *pWInfo; /* Information about the WHERE clause */
|
||||||
Vdbe *v; /* The virtual database engine */
|
Vdbe *v; /* The virtual database engine */
|
||||||
@ -80,11 +80,11 @@ void sqliteUpdate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Locate the table which we want to update. This table has to be
|
/* Locate the table which we want to update. This table has to be
|
||||||
** put in an IdList structure because some of the subroutines we
|
** put in an SrcList structure because some of the subroutines we
|
||||||
** will be calling are designed to work with multiple tables and expect
|
** will be calling are designed to work with multiple tables and expect
|
||||||
** an IdList* parameter instead of just a Table* parameter.
|
** an SrcList* parameter instead of just a Table* parameter.
|
||||||
*/
|
*/
|
||||||
pTabList = sqliteTableTokenToIdList(pParse, pTableName);
|
pTabList = sqliteTableTokenToSrcList(pParse, pTableName);
|
||||||
if( pTabList==0 ) goto update_cleanup;
|
if( pTabList==0 ) goto update_cleanup;
|
||||||
pTab = pTabList->a[0].pTab;
|
pTab = pTabList->a[0].pTab;
|
||||||
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
||||||
@ -391,7 +391,7 @@ void sqliteUpdate(
|
|||||||
update_cleanup:
|
update_cleanup:
|
||||||
sqliteFree(apIdx);
|
sqliteFree(apIdx);
|
||||||
sqliteFree(aXRef);
|
sqliteFree(aXRef);
|
||||||
sqliteIdListDelete(pTabList);
|
sqliteSrcListDelete(pTabList);
|
||||||
sqliteExprListDelete(pChanges);
|
sqliteExprListDelete(pChanges);
|
||||||
sqliteExprDelete(pWhere);
|
sqliteExprDelete(pWhere);
|
||||||
return;
|
return;
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
** But other routines are also provided to help in building up
|
** But other routines are also provided to help in building up
|
||||||
** a program instruction by instruction.
|
** a program instruction by instruction.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.c,v 1.146 2002/05/23 22:07:03 drh Exp $
|
** $Id: vdbe.c,v 1.147 2002/05/24 02:04:34 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -233,7 +233,7 @@ struct Vdbe {
|
|||||||
char **zStack; /* Text or binary values of the stack */
|
char **zStack; /* Text or binary values of the stack */
|
||||||
char **azColName; /* Becomes the 4th parameter to callbacks */
|
char **azColName; /* Becomes the 4th parameter to callbacks */
|
||||||
int nCursor; /* Number of slots in aCsr[] */
|
int nCursor; /* Number of slots in aCsr[] */
|
||||||
Cursor *aCsr; /* On element of this array for each open cursor */
|
Cursor *aCsr; /* One element of this array for each open cursor */
|
||||||
Keylist *pList; /* A list of ROWIDs */
|
Keylist *pList; /* A list of ROWIDs */
|
||||||
Sorter *pSort; /* A linked list of objects to be sorted */
|
Sorter *pSort; /* A linked list of objects to be sorted */
|
||||||
FILE *pFile; /* At most one open file handler */
|
FILE *pFile; /* At most one open file handler */
|
||||||
@ -3823,7 +3823,7 @@ case OP_ListReset: {
|
|||||||
|
|
||||||
/* Opcode: ListPush * * *
|
/* Opcode: ListPush * * *
|
||||||
**
|
**
|
||||||
** Save the current Vdbe list such that it can be restored by a PopList
|
** Save the current Vdbe list such that it can be restored by a ListPop
|
||||||
** opcode. The list is empty after this is executed.
|
** opcode. The list is empty after this is executed.
|
||||||
*/
|
*/
|
||||||
case OP_ListPush: {
|
case OP_ListPush: {
|
||||||
@ -3838,7 +3838,7 @@ case OP_ListPush: {
|
|||||||
|
|
||||||
/* Opcode: ListPop * * *
|
/* Opcode: ListPop * * *
|
||||||
**
|
**
|
||||||
** Restore the Vdbe list to the state it was in when PushList was last
|
** Restore the Vdbe list to the state it was in when ListPush was last
|
||||||
** executed.
|
** executed.
|
||||||
*/
|
*/
|
||||||
case OP_ListPop: {
|
case OP_ListPop: {
|
||||||
|
32
src/where.c
32
src/where.c
@ -13,7 +13,7 @@
|
|||||||
** the WHERE clause of SQL statements. Also found here are subroutines
|
** the WHERE clause of SQL statements. Also found here are subroutines
|
||||||
** to generate VDBE code to evaluate expressions.
|
** to generate VDBE code to evaluate expressions.
|
||||||
**
|
**
|
||||||
** $Id: where.c,v 1.45 2002/05/21 13:18:26 drh Exp $
|
** $Id: where.c,v 1.46 2002/05/24 02:04:34 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ static void exprAnalyze(int base, ExprInfo *pInfo){
|
|||||||
WhereInfo *sqliteWhereBegin(
|
WhereInfo *sqliteWhereBegin(
|
||||||
Parse *pParse, /* The parser context */
|
Parse *pParse, /* The parser context */
|
||||||
int base, /* VDBE cursor index for left-most table in pTabList */
|
int base, /* VDBE cursor index for left-most table in pTabList */
|
||||||
IdList *pTabList, /* A list of all tables */
|
SrcList *pTabList, /* A list of all tables to be scanned */
|
||||||
Expr *pWhere, /* The WHERE clause */
|
Expr *pWhere, /* The WHERE clause */
|
||||||
int pushKey /* If TRUE, leave the table key on the stack */
|
int pushKey /* If TRUE, leave the table key on the stack */
|
||||||
){
|
){
|
||||||
@ -178,12 +178,12 @@ WhereInfo *sqliteWhereBegin(
|
|||||||
ExprInfo aExpr[50]; /* The WHERE clause is divided into these expressions */
|
ExprInfo aExpr[50]; /* The WHERE clause is divided into these expressions */
|
||||||
|
|
||||||
/* Allocate space for aOrder[] and aiMem[]. */
|
/* Allocate space for aOrder[] and aiMem[]. */
|
||||||
aOrder = sqliteMalloc( sizeof(int) * pTabList->nId );
|
aOrder = sqliteMalloc( sizeof(int) * pTabList->nSrc );
|
||||||
|
|
||||||
/* Allocate and initialize the WhereInfo structure that will become the
|
/* Allocate and initialize the WhereInfo structure that will become the
|
||||||
** return value.
|
** return value.
|
||||||
*/
|
*/
|
||||||
pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nId*sizeof(WhereLevel) );
|
pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
|
||||||
if( sqlite_malloc_failed ){
|
if( sqlite_malloc_failed ){
|
||||||
sqliteFree(aOrder);
|
sqliteFree(aOrder);
|
||||||
sqliteFree(pWInfo);
|
sqliteFree(pWInfo);
|
||||||
@ -239,20 +239,20 @@ WhereInfo *sqliteWhereBegin(
|
|||||||
|
|
||||||
/* Figure out a good nesting order for the tables. aOrder[0] will
|
/* Figure out a good nesting order for the tables. aOrder[0] will
|
||||||
** be the index in pTabList of the outermost table. aOrder[1] will
|
** be the index in pTabList of the outermost table. aOrder[1] will
|
||||||
** be the first nested loop and so on. aOrder[pTabList->nId-1] will
|
** be the first nested loop and so on. aOrder[pTabList->nSrc-1] will
|
||||||
** be the innermost loop.
|
** be the innermost loop.
|
||||||
**
|
**
|
||||||
** Someday we will put in a good algorithm here to reorder the loops
|
** Someday we will put in a good algorithm here to reorder the loops
|
||||||
** for an effiecient query. But for now, just use whatever order the
|
** for an effiecient query. But for now, just use whatever order the
|
||||||
** tables appear in in the pTabList.
|
** tables appear in in the pTabList.
|
||||||
*/
|
*/
|
||||||
for(i=0; i<pTabList->nId; i++){
|
for(i=0; i<pTabList->nSrc; i++){
|
||||||
aOrder[i] = i;
|
aOrder[i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Figure out what index to use (if any) for each nested loop.
|
/* Figure out what index to use (if any) for each nested loop.
|
||||||
** Make pWInfo->a[i].pIdx point to the index to use for the i-th nested
|
** Make pWInfo->a[i].pIdx point to the index to use for the i-th nested
|
||||||
** loop where i==0 is the outer loop and i==pTabList->nId-1 is the inner
|
** loop where i==0 is the outer loop and i==pTabList->nSrc-1 is the inner
|
||||||
** loop.
|
** loop.
|
||||||
**
|
**
|
||||||
** If terms exist that use the ROWID of any table, then set the
|
** If terms exist that use the ROWID of any table, then set the
|
||||||
@ -267,7 +267,7 @@ WhereInfo *sqliteWhereBegin(
|
|||||||
** to the limit of 32 bits in an integer bitmask.
|
** to the limit of 32 bits in an integer bitmask.
|
||||||
*/
|
*/
|
||||||
loopMask = 0;
|
loopMask = 0;
|
||||||
for(i=0; i<pTabList->nId && i<ARRAYSIZE(aDirect); i++){
|
for(i=0; i<pTabList->nSrc && i<ARRAYSIZE(aDirect); i++){
|
||||||
int j;
|
int j;
|
||||||
int idx = aOrder[i];
|
int idx = aOrder[i];
|
||||||
Table *pTab = pTabList->a[idx].pTab;
|
Table *pTab = pTabList->a[idx].pTab;
|
||||||
@ -426,7 +426,7 @@ WhereInfo *sqliteWhereBegin(
|
|||||||
|
|
||||||
/* Open all tables in the pTabList and all indices used by those tables.
|
/* Open all tables in the pTabList and all indices used by those tables.
|
||||||
*/
|
*/
|
||||||
for(i=0; i<pTabList->nId; i++){
|
for(i=0; i<pTabList->nSrc; i++){
|
||||||
int openOp;
|
int openOp;
|
||||||
Table *pTab;
|
Table *pTab;
|
||||||
|
|
||||||
@ -449,7 +449,7 @@ WhereInfo *sqliteWhereBegin(
|
|||||||
/* Generate the code to do the search
|
/* Generate the code to do the search
|
||||||
*/
|
*/
|
||||||
loopMask = 0;
|
loopMask = 0;
|
||||||
for(i=0; i<pTabList->nId; i++){
|
for(i=0; i<pTabList->nSrc; i++){
|
||||||
int j, k;
|
int j, k;
|
||||||
int idx = aOrder[i];
|
int idx = aOrder[i];
|
||||||
Index *pIdx;
|
Index *pIdx;
|
||||||
@ -473,7 +473,7 @@ WhereInfo *sqliteWhereBegin(
|
|||||||
brk = pLevel->brk = sqliteVdbeMakeLabel(v);
|
brk = pLevel->brk = sqliteVdbeMakeLabel(v);
|
||||||
cont = pLevel->cont = brk;
|
cont = pLevel->cont = brk;
|
||||||
sqliteVdbeAddOp(v, OP_MustBeInt, 0, brk);
|
sqliteVdbeAddOp(v, OP_MustBeInt, 0, brk);
|
||||||
if( i==pTabList->nId-1 && pushKey ){
|
if( i==pTabList->nSrc-1 && pushKey ){
|
||||||
/* Note: The OP_Dup below will cause the recno to be left on the
|
/* Note: The OP_Dup below will cause the recno to be left on the
|
||||||
** stack if the record does not exists and the OP_NotExists jump is
|
** stack if the record does not exists and the OP_NotExists jump is
|
||||||
** taken. This violates a general rule of the VDBE that you should
|
** taken. This violates a general rule of the VDBE that you should
|
||||||
@ -536,7 +536,7 @@ WhereInfo *sqliteWhereBegin(
|
|||||||
start = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
|
start = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
|
||||||
sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk);
|
sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk);
|
||||||
sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
|
sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
|
||||||
if( i==pTabList->nId-1 && pushKey ){
|
if( i==pTabList->nSrc-1 && pushKey ){
|
||||||
haveKey = 1;
|
haveKey = 1;
|
||||||
}else{
|
}else{
|
||||||
sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0);
|
sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0);
|
||||||
@ -759,7 +759,7 @@ WhereInfo *sqliteWhereBegin(
|
|||||||
sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk);
|
sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk);
|
||||||
}
|
}
|
||||||
sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
|
sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
|
||||||
if( i==pTabList->nId-1 && pushKey ){
|
if( i==pTabList->nSrc-1 && pushKey ){
|
||||||
haveKey = 1;
|
haveKey = 1;
|
||||||
}else{
|
}else{
|
||||||
sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0);
|
sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0);
|
||||||
@ -805,9 +805,9 @@ void sqliteWhereEnd(WhereInfo *pWInfo){
|
|||||||
int i;
|
int i;
|
||||||
int base = pWInfo->base;
|
int base = pWInfo->base;
|
||||||
WhereLevel *pLevel;
|
WhereLevel *pLevel;
|
||||||
IdList *pTabList = pWInfo->pTabList;
|
SrcList *pTabList = pWInfo->pTabList;
|
||||||
|
|
||||||
for(i=pTabList->nId-1; i>=0; i--){
|
for(i=pTabList->nSrc-1; i>=0; i--){
|
||||||
pLevel = &pWInfo->a[i];
|
pLevel = &pWInfo->a[i];
|
||||||
sqliteVdbeResolveLabel(v, pLevel->cont);
|
sqliteVdbeResolveLabel(v, pLevel->cont);
|
||||||
if( pLevel->op!=OP_Noop ){
|
if( pLevel->op!=OP_Noop ){
|
||||||
@ -816,7 +816,7 @@ void sqliteWhereEnd(WhereInfo *pWInfo){
|
|||||||
sqliteVdbeResolveLabel(v, pLevel->brk);
|
sqliteVdbeResolveLabel(v, pLevel->brk);
|
||||||
}
|
}
|
||||||
sqliteVdbeResolveLabel(v, pWInfo->iBreak);
|
sqliteVdbeResolveLabel(v, pWInfo->iBreak);
|
||||||
for(i=0; i<pTabList->nId; i++){
|
for(i=0; i<pTabList->nSrc; i++){
|
||||||
if( pTabList->a[i].pTab->isTransient ) continue;
|
if( pTabList->a[i].pTab->isTransient ) continue;
|
||||||
pLevel = &pWInfo->a[i];
|
pLevel = &pWInfo->a[i];
|
||||||
sqliteVdbeAddOp(v, OP_Close, base+i, 0);
|
sqliteVdbeAddOp(v, OP_Close, base+i, 0);
|
||||||
|
Reference in New Issue
Block a user