mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Bug fixes in the VIEW implementation. (CVS 396)
FossilOrigin-Name: 668ef6380eba256ef82477b63aef850249a619a0
This commit is contained in:
14
src/build.c
14
src/build.c
@ -25,7 +25,7 @@
|
||||
** ROLLBACK
|
||||
** PRAGMA
|
||||
**
|
||||
** $Id: build.c,v 1.79 2002/02/23 02:32:10 drh Exp $
|
||||
** $Id: build.c,v 1.80 2002/02/27 01:47:12 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -824,6 +824,7 @@ void sqliteCreateView(
|
||||
pSelTab->nCol = 0;
|
||||
pSelTab->aCol = 0;
|
||||
sqliteDeleteTable(0, pSelTab);
|
||||
sqliteSelectUnbind(pSelect);
|
||||
sEnd = pParse->sLastToken;
|
||||
if( sEnd.z[0]!=0 && sEnd.z[0]!=';' ){
|
||||
sEnd.z += sEnd.n;
|
||||
@ -1341,22 +1342,15 @@ void sqliteIdListDelete(IdList *pList){
|
||||
for(i=0; i<pList->nId; i++){
|
||||
sqliteFree(pList->a[i].zName);
|
||||
sqliteFree(pList->a[i].zAlias);
|
||||
|
||||
/* If the pSelect field is set and is not pointing to the Select
|
||||
** structure that defines a VIEW, then the Select is for a subquery
|
||||
** and should be deleted. Do not delete VIEWs, however.
|
||||
*/
|
||||
if( pList->a[i].pSelect &&
|
||||
(pList->a[i].pTab==0 || pList->a[i].pTab->pSelect==0) ){
|
||||
sqliteSelectDelete(pList->a[i].pSelect);
|
||||
if( pList->a[i].pTab && pList->a[i].pTab->isTransient ){
|
||||
sqliteDeleteTable(0, pList->a[i].pTab);
|
||||
}
|
||||
sqliteSelectDelete(pList->a[i].pSelect);
|
||||
}
|
||||
sqliteFree(pList->a);
|
||||
sqliteFree(pList);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** The COPY command is for compatibility with PostgreSQL and specificially
|
||||
** for the ability to read the output of pg_dump. The format is as
|
||||
|
87
src/expr.c
87
src/expr.c
@ -12,7 +12,7 @@
|
||||
** This file contains routines used for analyzing expressions and
|
||||
** for generating VDBE code that evaluates expressions in SQLite.
|
||||
**
|
||||
** $Id: expr.c,v 1.45 2002/02/26 23:55:31 drh Exp $
|
||||
** $Id: expr.c,v 1.46 2002/02/27 01:47:12 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -147,6 +147,91 @@ void sqliteSelectMoveStrings(Select *pSelect, int offset){
|
||||
sqliteSelectMoveStrings(pSelect->pPrior, offset);
|
||||
}
|
||||
|
||||
/*
|
||||
** The following group of routines make deep copies of expressions,
|
||||
** expression lists, ID lists, and select statements. The copies can
|
||||
** be deleted (by being passed to their respective ...Delete() routines)
|
||||
** without effecting the originals.
|
||||
**
|
||||
** Note, however, that the Expr.token.z and Expr.span.z fields point to
|
||||
** string space that is allocated separately from the expression tree
|
||||
** itself. These routines do NOT duplicate that string space.
|
||||
**
|
||||
** The expression list and ID list return by sqliteExprListDup() and
|
||||
** sqliteIdListDup() can not be further expanded by subsequent calls
|
||||
** to sqliteExprListAppend() or sqliteIdListAppend().
|
||||
**
|
||||
** Any tables that the ID list might point to are not duplicated.
|
||||
*/
|
||||
Expr *sqliteExprDup(Expr *p){
|
||||
Expr *pNew;
|
||||
if( p==0 ) return 0;
|
||||
pNew = sqliteMalloc( sizeof(*p) );
|
||||
if( pNew==0 ) return 0;
|
||||
pNew->op = p->op;
|
||||
pNew->pLeft = sqliteExprDup(p->pLeft);
|
||||
pNew->pRight = sqliteExprDup(p->pRight);
|
||||
pNew->pList = sqliteExprListDup(p->pList);
|
||||
pNew->token = p->token;
|
||||
pNew->span = p->span;
|
||||
pNew->pSelect = sqliteSelectDup(p->pSelect);
|
||||
return pNew;
|
||||
}
|
||||
ExprList *sqliteExprListDup(ExprList *p){
|
||||
ExprList *pNew;
|
||||
int i;
|
||||
if( p==0 ) return 0;
|
||||
pNew = sqliteMalloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return 0;
|
||||
pNew->nExpr = p->nExpr;
|
||||
pNew->a = sqliteMalloc( p->nExpr*sizeof(p->a[0]) );
|
||||
for(i=0; i<p->nExpr; i++){
|
||||
pNew->a[i].pExpr = sqliteExprDup(p->a[i].pExpr);
|
||||
pNew->a[i].zName = sqliteStrDup(p->a[i].zName);
|
||||
pNew->a[i].sortOrder = p->a[i].sortOrder;
|
||||
pNew->a[i].isAgg = p->a[i].isAgg;
|
||||
pNew->a[i].done = 0;
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
IdList *sqliteIdListDup(IdList *p){
|
||||
IdList *pNew;
|
||||
int i;
|
||||
if( p==0 ) return 0;
|
||||
pNew = sqliteMalloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return 0;
|
||||
pNew->nId = p->nId;
|
||||
pNew->a = sqliteMalloc( p->nId*sizeof(p->a[0]) );
|
||||
for(i=0; i<p->nId; i++){
|
||||
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].pTab = 0;
|
||||
pNew->a[i].pSelect = sqliteSelectDup(p->a[i].pSelect);
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
Select *sqliteSelectDup(Select *p){
|
||||
Select *pNew;
|
||||
if( p==0 ) return 0;
|
||||
pNew = sqliteMalloc( sizeof(*p) );
|
||||
if( pNew==0 ) return 0;
|
||||
pNew->isDistinct = p->isDistinct;
|
||||
pNew->pEList = sqliteExprListDup(p->pEList);
|
||||
pNew->pSrc = sqliteIdListDup(p->pSrc);
|
||||
pNew->pWhere = sqliteExprDup(p->pWhere);
|
||||
pNew->pGroupBy = sqliteExprListDup(p->pGroupBy);
|
||||
pNew->pHaving = sqliteExprDup(p->pHaving);
|
||||
pNew->pOrderBy = sqliteExprListDup(p->pOrderBy);
|
||||
pNew->op = p->op;
|
||||
pNew->pPrior = sqliteSelectDup(p->pPrior);
|
||||
pNew->nLimit = p->nLimit;
|
||||
pNew->nOffset = p->nOffset;
|
||||
pNew->zSelect = 0;
|
||||
return pNew;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Add a new element to the end of an expression list. If pList is
|
||||
** initially NULL, then create a new expression list.
|
||||
|
34
src/select.c
34
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.66 2002/02/24 03:25:16 drh Exp $
|
||||
** $Id: select.c,v 1.67 2002/02/27 01:47:12 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -397,7 +397,7 @@ static int fillInColumnList(Parse *pParse, Select *p){
|
||||
return 1;
|
||||
}
|
||||
if( pTab->pSelect ){
|
||||
pTabList->a[i].pSelect = pTab->pSelect;
|
||||
pTabList->a[i].pSelect = sqliteSelectDup(pTab->pSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -456,6 +456,36 @@ static int fillInColumnList(Parse *pParse, Select *p){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine recursively unlinks the Select.pSrc.a[].pTab pointers
|
||||
** in a select structure. It just sets the pointers to NULL. This
|
||||
** routine is recursive in the sense that if the Select.pSrc.a[].pSelect
|
||||
** pointer is not NULL, this routine is called recursively on that pointer.
|
||||
**
|
||||
** This routine is called on the Select structure that defines a
|
||||
** VIEW in order to undo any bindings to tables. This is necessary
|
||||
** because those tables might be DROPed by a subsequent SQL command.
|
||||
*/
|
||||
void sqliteSelectUnbind(Select *p){
|
||||
int i;
|
||||
IdList *pSrc = p->pSrc;
|
||||
Table *pTab;
|
||||
if( p==0 ) return;
|
||||
for(i=0; i<pSrc->nId; i++){
|
||||
if( (pTab = pSrc->a[i].pTab)!=0 ){
|
||||
if( pTab->isTransient ){
|
||||
sqliteDeleteTable(0, pTab);
|
||||
sqliteSelectDelete(pSrc->a[i].pSelect);
|
||||
pSrc->a[i].pSelect = 0;
|
||||
}
|
||||
pSrc->a[i].pTab = 0;
|
||||
if( pSrc->a[i].pSelect ){
|
||||
sqliteSelectUnbind(pSrc->a[i].pSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine associates entries in an ORDER BY expression list with
|
||||
** columns in a result. For each ORDER BY expression, the opcode of
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.93 2002/02/24 03:25:16 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.94 2002/02/27 01:47:12 drh Exp $
|
||||
*/
|
||||
#include "sqlite.h"
|
||||
#include "hash.h"
|
||||
@ -605,6 +605,7 @@ int sqliteSelect(Parse*, Select*, int, int);
|
||||
Select *sqliteSelectNew(ExprList*,IdList*,Expr*,ExprList*,Expr*,ExprList*,
|
||||
int,int,int);
|
||||
void sqliteSelectDelete(Select*);
|
||||
void sqliteSelectUnbind(Select*);
|
||||
Table *sqliteTableNameToTable(Parse*, const char*);
|
||||
IdList *sqliteTableTokenToIdList(Parse*, Token*);
|
||||
void sqliteDeleteFrom(Parse*, Token*, Expr*);
|
||||
@ -646,5 +647,9 @@ void sqliteEndWriteOperation(Parse*);
|
||||
void sqliteExprMoveStrings(Expr*, int);
|
||||
void sqliteExprListMoveStrings(ExprList*, int);
|
||||
void sqliteSelectMoveStrings(Select*, int);
|
||||
Expr *sqliteExprDup(Expr*);
|
||||
ExprList *sqliteExprListDup(ExprList*);
|
||||
IdList *sqliteIdListDup(IdList*);
|
||||
Select *sqliteSelectDup(Select*);
|
||||
UserFunc *sqliteFindUserFunction(sqlite*,const char*,int,int,int);
|
||||
void sqliteRegisterBuildinFunctions(sqlite*);
|
||||
|
10
src/util.c
10
src/util.c
@ -14,7 +14,7 @@
|
||||
** This file contains functions for allocating memory, comparing
|
||||
** strings, and stuff like that.
|
||||
**
|
||||
** $Id: util.c,v 1.37 2002/02/14 21:42:51 drh Exp $
|
||||
** $Id: util.c,v 1.38 2002/02/27 01:47:12 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdarg.h>
|
||||
@ -183,12 +183,16 @@ void sqliteStrRealloc(char **pz){
|
||||
** Make a copy of a string in memory obtained from sqliteMalloc()
|
||||
*/
|
||||
char *sqliteStrDup_(const char *z, char *zFile, int line){
|
||||
char *zNew = sqliteMalloc_(strlen(z)+1, zFile, line);
|
||||
char *zNew;
|
||||
if( z==0 ) return 0;
|
||||
zNew = sqliteMalloc_(strlen(z)+1, zFile, line);
|
||||
if( zNew ) strcpy(zNew, z);
|
||||
return zNew;
|
||||
}
|
||||
char *sqliteStrNDup_(const char *z, int n, char *zFile, int line){
|
||||
char *zNew = sqliteMalloc_(n+1, zFile, line);
|
||||
char *zNew;
|
||||
if( z==0 ) return 0;
|
||||
zNew = sqliteMalloc_(n+1, zFile, line);
|
||||
if( zNew ){
|
||||
memcpy(zNew, z, n);
|
||||
zNew[n] = 0;
|
||||
|
Reference in New Issue
Block a user