Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -3570,16 +3570,25 @@ /* ** Append a new element to the given IdList. Create a new IdList if ** need be. ** ** A new IdList is returned, or NULL if malloc() fails. +** +** The zName must have been obtained from sqlite3DbMalloc(). This routine +** accepts ownership of the zName string and will ensure that it is freed +** when no longer in use. */ -IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){ +IdList *sqlite3IdListAppend( + Parse *pParse, /* Parsing context */ + IdList *pList, /* ID list to append to */ + char *zName /* Token to append */ +){ int i; + sqlite3 *db = pParse->db; if( pList==0 ){ pList = sqlite3DbMallocZero(db, sizeof(IdList) ); - if( pList==0 ) return 0; + if( pList==0 ) goto id_list_append_fail; } pList->a = sqlite3ArrayAllocate( db, pList->a, sizeof(pList->a[0]), @@ -3586,14 +3595,18 @@ &pList->nId, &i ); if( i<0 ){ sqlite3IdListDelete(db, pList); - return 0; + goto id_list_append_fail; } - pList->a[i].zName = sqlite3NameFromToken(db, pToken); + pList->a[i].zName = zName; return pList; + +id_list_append_fail: + sqlite3DbFree(db, zName); + return 0; } /* ** Delete an IdList. */ Index: src/parse.y ================================================================== --- src/parse.y +++ src/parse.y @@ -202,14 +202,18 @@ %left STAR SLASH REM. %left CONCAT. %left COLLATE. %right BITNOT. -// An IDENTIFIER can be a generic identifier, or one of several +// An "id" can be a generic identifier, or one of several // keywords. Any non-standard keyword can also be an identifier. // %token_class id ID|INDEXED. + +// A "number" can be either an integer or a floating point value +%token_class number INTEGER|FLOAT. + // The following directive causes tokens ABORT, AFTER, ASC, etc. to // fallback to ID if they will not parse as their original value. // This obviates the need for the "id" nonterminal. // @@ -252,12 +256,12 @@ A.n = (int)(&Y.z[Y.n] - A.z); } %type typename {Token} typename(A) ::= ids(A). typename(A) ::= typename(A) ids(Y). {A.n=Y.n+(int)(Y.z-A.z);} -signed ::= plus_num. -signed ::= minus_num. +signed ::= PLUS|MINUS number. +signed ::= number. // "carglist" is a list of additional constraints that come after the // column name and column type in a CREATE TABLE statement. // carglist ::= carglist ccons. @@ -805,16 +809,17 @@ %type idlist_opt {IdList*} %destructor idlist_opt {sqlite3IdListDelete(pParse->db, $$);} %type idlist {IdList*} %destructor idlist {sqlite3IdListDelete(pParse->db, $$);} -idlist_opt(A) ::= . {A = 0;} +idlist_opt(A) ::= . {A = 0;} idlist_opt(A) ::= LP idlist(X) RP. {A = X;} idlist(A) ::= idlist(A) COMMA nm(Y). - {A = sqlite3IdListAppend(pParse->db,A,&Y);} + {A = sqlite3IdListAppend(pParse,A,sqlite3NameFromToken(pParse->db,&Y));} idlist(A) ::= nm(Y). - {A = sqlite3IdListAppend(pParse->db,0,&Y); /*A-overwrites-Y*/} + {A = sqlite3IdListAppend(pParse,0,sqlite3NameFromToken(pParse->db,&Y)); + /*A-overwrites-Y*/} /////////////////////////// Expression Processing ///////////////////////////// // %type expr {ExprSpan} @@ -1322,28 +1327,36 @@ %endif SQLITE_OMIT_VACUUM ///////////////////////////// The PRAGMA command ///////////////////////////// // %ifndef SQLITE_OMIT_PRAGMA -cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);} -cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);} -cmd ::= PRAGMA nm(X) dbnm(Z) LP nmnum(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);} -cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). - {sqlite3Pragma(pParse,&X,&Z,&Y,1);} -cmd ::= PRAGMA nm(X) dbnm(Z) LP minus_num(Y) RP. - {sqlite3Pragma(pParse,&X,&Z,&Y,1);} - -nmnum(A) ::= plus_num(A). -nmnum(A) ::= nm(A). -nmnum(A) ::= ON(A). -nmnum(A) ::= DELETE(A). -nmnum(A) ::= DEFAULT(A). -%endif SQLITE_OMIT_PRAGMA -%token_class number INTEGER|FLOAT. -plus_num(A) ::= PLUS number(X). {A = X;} -plus_num(A) ::= number(A). -minus_num(A) ::= MINUS number(X). {A = X;} +cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0);} +cmd ::= PRAGMA nm(X) dbnm(Z) EQ pragma_arglist(Y). + {sqlite3Pragma(pParse,&X,&Z,Y);} +cmd ::= PRAGMA nm(X) dbnm(Z) LP pragma_arglist(Y) RP. + {sqlite3Pragma(pParse,&X,&Z,Y);} + +%type pragma_arglist {IdList*} +%destructor pragma_arglist {sqlite3IdListDelete(pParse->db,$$);} + +pragma_arglist(A) ::= pragma_arg(X). + { A = sqlite3IdListAppend(pParse,0,X)/*A-overwrites-X*/; } +pragma_arglist(A) ::= pragma_arglist(A) COMMA pragma_arg(Y). + { A = sqlite3IdListAppend(pParse,A,Y); } + +%type pragma_arg {char*} +%destructor pragma_arg {sqlite3DbFree(pParse->db,$$);} +pragma_arg(A) ::= number(X). + {A = sqlite3NameFromToken(pParse->db,&X);/*A-overwrites-X*/} +pragma_arg(A) ::= nm(X). + {A = sqlite3NameFromToken(pParse->db,&X);/*A-overwrites-X*/} +pragma_arg(A) ::= ON|DELETE|DEFAULT(X). + {A = sqlite3NameFromToken(pParse->db,&X);/*A-overwrites-X*/} +pragma_arg(A) ::= PLUS number(X). {A = sqlite3NameFromToken(pParse->db,&X);} +pragma_arg(A) ::= MINUS number(X). {A = sqlite3MPrintf(pParse->db,"-%T",&X);} + +%endif SQLITE_OMIT_PRAGMA //////////////////////////// The CREATE TRIGGER command ///////////////////// %ifndef SQLITE_OMIT_TRIGGER cmd ::= createkw trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). { Index: src/pragma.c ================================================================== --- src/pragma.c +++ src/pragma.c @@ -280,26 +280,21 @@ /* ** Process a pragma statement. ** ** Pragmas are of this form: ** -** PRAGMA [schema.]id [= value] -** -** The identifier might also be a string. The value is a string, and -** identifier, or a number. If minusFlag is true, then the value is -** a number that was preceded by a minus sign. +** PRAGMA [schema.]id [= value-list] ** ** If the left side is "database.id" then pId1 is the database name ** and pId2 is the id. If the left side is just "id" then pId1 is the ** id and pId2 is any empty string. */ void sqlite3Pragma( Parse *pParse, Token *pId1, /* First part of [schema.]id field */ Token *pId2, /* Second part of [schema.]id field, or NULL */ - Token *pValue, /* Token for , or NULL */ - int minusFlag /* True if a '-' sign preceded */ + IdList *pValues /* The value-list arguments. NULL if omitted */ ){ char *zLeft = 0; /* Nul-terminated UTF-8 string */ char *zRight = 0; /* Nul-terminated UTF-8 string , or NULL */ const char *zDb = 0; /* The database name */ Token *pId; /* Pointer to token */ @@ -310,18 +305,18 @@ sqlite3 *db = pParse->db; /* The database connection */ Db *pDb; /* The specific database being pragmaed */ Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */ const struct sPragmaNames *pPragma; - if( v==0 ) return; + if( v==0 ) goto pragma_out; sqlite3VdbeRunOnlyOnce(v); pParse->nMem = 2; /* Interpret the [schema.] part of the pragma statement. iDb is the ** index of the database this pragma is being applied to in db.aDb[]. */ iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId); - if( iDb<0 ) return; + if( iDb<0 ) goto pragma_out; pDb = &db->aDb[iDb]; /* If the temp database has been explicitly named as part of the ** pragma, make sure it is open. */ @@ -328,16 +323,12 @@ if( iDb==1 && sqlite3OpenTempDatabase(pParse) ){ return; } zLeft = sqlite3NameFromToken(db, pId); - if( !zLeft ) return; - if( minusFlag ){ - zRight = sqlite3MPrintf(db, "-%T", pValue); - }else{ - zRight = sqlite3NameFromToken(db, pValue); - } + if( !zLeft ) goto pragma_out; + if( pValues ) zRight = pValues->a[0].zName; assert( pId2 ); zDb = pId2->n>0 ? pDb->zDbSName : 0; if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){ goto pragma_out; @@ -1982,9 +1973,9 @@ } /* End of the PRAGMA switch */ pragma_out: sqlite3DbFree(db, zLeft); - sqlite3DbFree(db, zRight); + sqlite3IdListDelete(db, pValues); } #endif /* SQLITE_OMIT_PRAGMA */ Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -3564,11 +3564,11 @@ void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*); void sqlite3ExprListDelete(sqlite3*, ExprList*); u32 sqlite3ExprListFlags(const ExprList*); int sqlite3Init(sqlite3*, char**); int sqlite3InitCallback(void*, int, char**, char**); -void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); +void sqlite3Pragma(Parse*,Token*,Token*,IdList*); void sqlite3ResetAllSchemasOfConnection(sqlite3*); void sqlite3ResetOneSchema(sqlite3*,int); void sqlite3CollapseDatabaseArray(sqlite3*); void sqlite3CommitInternalChanges(sqlite3*); void sqlite3DeleteColumnNames(sqlite3*,Table*); @@ -3639,11 +3639,11 @@ # define sqlite3AutoincrementBegin(X) # define sqlite3AutoincrementEnd(X) #endif void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int); void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*); -IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*); +IdList *sqlite3IdListAppend(Parse*, IdList*, char*); int sqlite3IdListIndex(IdList*,const char*); SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int); SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*); SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*, Select*, Expr*, IdList*);