-C In\sext/wasm,\sadd\sthe\sability\sto\somit\sspecific\sJS\sAPIs\sand\sVFSes\sat\sbuild-time.
-D 2026-07-02T09:52:03.709
+C Experimental\swork\son\simplementing\san\sEXCLUDE\sclause\sfollowing\s"*"\nwildcards\sin\sa\sSELECT\sstatement.\s\sParsing\sonly\sat\sthis\spoint.
+D 2026-07-03T00:56:05.259
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F src/os_win.h c06ccc3a090cf54202ea58981c298817f3309d4c9e4d52ad0a02927346493721
F src/pager.c 678ee3b68638ee427cc1b071b11181d0f2a827f6cb4d6ec7c12d5fa5f6a752d0
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
-F src/parse.y d5a3c5b0277a441c38b35071c05e2b61ff5fc918a63309c809f4b6706179c320
+F src/parse.y dc11c53d183d26f1931a30f63b9b3a9a2311c50ec1ff6b7bed210a53767c7e1e
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
F src/pcache.h 092b758d2c5e4dabb30eae46d8dfad77c0f70b16bf3ff1943f7a232b0fe0d4ba
F src/pcache1.c d7ee0f95992501a65379f620b3de1430b64e52e397769938668a9fd9dd1c8145
F src/sqlite.h.in d9ec41feb4cd804e68b174328b43beb3f1f71bba13e1c7a439efb826d301cccc
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 0efd4723bad9124ea1f581d9f1ea0254ac1c6f3e5fb29e4f3dcf36c72485a456
-F src/sqliteInt.h 92563b8edc673513b82d87bf6a8d7aeb554b2c7b7d5e30992fbca04010db79ac
+F src/sqliteInt.h e0324e481eaa7adaf5fc2d79caae838b1d88d3466c50453345d4628b003f3db6
F src/sqliteLimit.h c70656b67ab5b96741a8f1c812bdd80c81f2b1c1e443d0cc3ea8c33bb1f1a092
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 85d8b9f05f78211c61e3739ab5db761d7118766d1916ae7f2764735106bc4e13
F src/tokenize.c e9d52d9f7374d82dadcd11726bea8a597d43709d6672704f3f0375bf1d726912
-F src/treeview.c feaa59f14db4f7b5aacca9c5ad5aeb562c1f98262c1ffd74371f4186ade91fc5
+F src/treeview.c d4949e9bb73b5ee6d850213225a30d4f8f2988582d4f7166080644aadcc3e94c
F src/trigger.c 5028874dd1f4fd3085bacd55c30114b5ad651525508656f65af09adf227181d5
F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
F src/upsert.c dd9f0fcccbfb4f20e1026a21a7254ba3f2c08e9cfa92affaff5b5ec3b00ea549
F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 88901fffcd445ccb97e4e379ea15d8b06d87b8170cad0f717c909944ff21851f 225dd27e147b46e85097ada7234a307f55842d98155cd36fe00da57744598bc3
-R d20cfce4969b948014d3a3d610a966ce
-T +closed 225dd27e147b46e85097ada7234a307f55842d98155cd36fe00da57744598bc3 Closed\sby\sintegrate-merge.
-U stephan
-Z 4776f4f7741018f2b4629b3adc43c7dd
+P 0d70a15c3b35e9af3052042cd5332db1b38a66416f1c3c8a50d342395bf22c01
+R fbfb38b4a2d1f59e008a86ce344506fc
+T *branch * exclude-clause
+T *sym-exclude-clause *
+T -sym-trunk *
+U drh
+Z 085c7684bdb90daee11e1c534e7f72a6
# Remove this line to create a well-formed Fossil manifest.
if( Y.n>0 ) sqlite3ExprListSetName(pParse, A, &Y, 1);
sqlite3ExprListSetSpan(pParse,A,B,Z);
}
-selcollist(A) ::= sclp(A) scanpt STAR(X). {
- Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
+%include {
+ /* Construct a TK_ASTERISK Expr for the "*" wildcard in a result set
+ ** specification, with its optional EXCLUDE clause
+ */
+ static Expr *parserWildcardExpr(sqlite3 *db, ExprList *pExclude){
+ Expr *p = sqlite3Expr(db, TK_ASTERISK, 0);
+ if( pExclude ){
+ if( p ){
+ p->x.pList = pExclude;
+ }else{
+ sqlite3ExprListDelete(db, pExclude);
+ }
+ }
+ return p;
+ }
+}
+selcollist(A) ::= sclp(A) scanpt STAR(X) colexcl(E). {
+ Expr *p = parserWildcardExpr(pParse->db, E);
sqlite3ExprSetErrorOffset(p, (int)(X.z - pParse->zTail));
A = sqlite3ExprListAppend(pParse, A, p);
}
-selcollist(A) ::= sclp(A) scanpt nm(X) DOT STAR(Y). {
+selcollist(A) ::= sclp(A) scanpt nm(X) DOT STAR(Y) colexcl(E). {
Expr *pRight, *pLeft, *pDot;
- pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
+ pRight = parserWildcardExpr(pParse->db, E);
sqlite3ExprSetErrorOffset(pRight, (int)(Y.z - pParse->zTail));
pLeft = tokenExpr(pParse, TK_ID, X);
pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
A = sqlite3ExprListAppend(pParse,A, pDot);
}
+// The colexcl nonterminal represents the EXCLUDE clause that can
+// optionally follow the "*" wildcard in the result set of a SELECT.
+// Example:
+//
+// SELECT * (EXCLUDE (a, b)
+// REPLACE (c WITH x+y, d WITH z*2)
+// RENAME (e AS ee, f AS foo))
+// FROM t ...
+//
+// The value is an ExprList with one entry for each exluded, replaced, or
+// renamed column, with ExprList_tiem fields set as follows:
+//
+// ExprList_item.zEName: Name of the column
+// ExprList_item.fg.eEName: One of ENAME_EXCLUDE, ENAME_REPLACE,
+// or ENAME_RENAME
+// ExprList_item.pExpr: If ENAME_EXCLUDE: NULL
+// If ENAME_REPLACE: Substitute expr
+// If ENAME_RENAME: TK_RENAME expr with new
+// name u.zToken
+//
+%type colexcl {ExprList*}
+%destructor colexcl {sqlite3ExprListDelete(pParse->db, $$);}
+%type cexcllist {ExprList*}
+%destructor cexcllist {sqlite3ExprListDelete(pParse->db, $$);}
+%type cexclitem {ExprList*}
+%destructor cexclitem {sqlite3ExprListDelete(pParse->db, $$);}
+%type cexclreplace {ExprList*}
+%destructor cexclreplace {sqlite3ExprListDelete(pParse->db, $$);}
+%type cexclrename {ExprList*}
+%destructor cexclrename {sqlite3ExprListDelete(pParse->db, $$);}
+
+colexcl(A) ::= . {A = 0;}
+colexcl(A) ::= cexclitem(A).
+colexcl(A) ::= LP cexcllist(X) RP. {A = X;}
+cexcllist(A) ::= cexclitem(A).
+cexcllist(A) ::= cexcllist(A) cexclitem(X).
+ {A = parserExcludeConcat(pParse,A,X);}
+cexclitem(A) ::= EXCLUDE LP idlist(X) RP.
+ {A = parserExcludeIdList(pParse,X);}
+cexclitem(A) ::= REPLACE LP cexclreplace(X) RP. {A = X;}
+cexclitem(A) ::= RENAME LP cexclrename(X) RP. {A = X;}
+cexclreplace(A) ::= nm(X) WITH expr(Y).
+ {A = parserExcludeExpr(pParse,0,&X,Y,ENAME_REPLACE);}
+cexclreplace(A) ::= cexclreplace(A) COMMA nm(X) WITH expr(Y).
+ {A = parserExcludeExpr(pParse,A,&X,Y,ENAME_REPLACE);}
+cexclrename(A) ::= nm(X) AS nm(Y). {
+ Expr *p = tokenExpr(pParse, TK_RENAME, Y);
+ A = parserExcludeExpr(pParse,0,&X,p,ENAME_RENAME);
+}
+cexclrename(A) ::= cexclrename(A) COMMA nm(X) AS nm(Y). {
+ Expr *p = tokenExpr(pParse, TK_RENAME, Y);
+ A = parserExcludeExpr(pParse,A,&X,p,ENAME_RENAME);
+}
+%include {
+ /* Append the pSrc ExprList onto the end of pDest.
+ ** Free pSrc when done. */
+ static ExprList *parserExcludeConcat(
+ Parse *pParse, /* Parsing context */
+ ExprList *pDest, /* Append to this ExprList */
+ ExprList *pSrc /* Take terms off of this ExprList */
+ ){
+ int i;
+ if( pSrc==0 ) return pDest;
+ for(i=0; i<pSrc->nExpr; i++){
+ pDest = sqlite3ExprListAppend(pParse, pDest, 0);
+ if( pDest ){
+ int j = pDest->nExpr - 1;
+ pDest->a[j] = pSrc->a[i];
+ pSrc->a[i].pExpr = 0;
+ pSrc->a[i].zEName = 0;
+ }
+ }
+ sqlite3ExprListDelete(pParse->db, pSrc);
+ return pDest;
+ }
+ /* Convert an IdList in pSrc into an EXCLUDE ExprList and return
+ ** the ExprList. Free pSrc when done */
+ static ExprList *parserExcludeIdList(
+ Parse *pParse, /* Parsing context */
+ IdList *pSrc /* Identifiers come from this list */
+ ){
+ int i;
+ ExprList *pDest = 0;
+ if( pSrc==0 ) return 0;
+ for(i=0; i<pSrc->nId; i++){
+ pDest = sqlite3ExprListAppend(pParse, pDest, 0);
+ if( pDest ){
+ int j = pDest->nExpr - 1;
+ pDest->a[j].zEName = pSrc->a[i].zName;
+ pDest->a[j].fg.eEName = ENAME_EXCLUDE;
+ pSrc->a[i].zName = 0;
+ }
+ }
+ sqlite3IdListDelete(pParse->db, pSrc);
+ return pDest;
+ }
+ /* Add a single new REPLACE or RENAME term into the EXCLUDE ExprList
+ ** in pDest. */
+ static ExprList *parserExcludeExpr(
+ Parse *pParse, /* Parsing context */
+ ExprList *pDest, /* Append one term to this ExprList */
+ Token *pName, /* Name of the column to be replaced */
+ Expr *pExpr, /* Replacement expression */
+ int eEName /* ENAME_REPLACE or ENAME_RENAME */
+ ){
+ pDest = sqlite3ExprListAppend(pParse, pDest, pExpr);
+ sqlite3ExprListSetName(pParse, pDest, pName, 1);
+ if( pDest ){
+ pDest->a[pDest->nExpr-1].fg.eEName = eEName;
+ }
+ return pDest;
+ }
+}
// An option "AS <id>" phrase that can follow one of the expressions that
// define the result set, or one of the tables in the FROM clause.
//
**
** ENAME_SPAN Text of the original result set
** expression.
+**
+** ENAME_EXCLUDE Column name that is part of an
+** ENAME_REPLACE (EXCLUDE(..)) expression following
+** ENAME_RENAME the "*" wildcard in a SELECT result set
*/
struct ExprList {
int nExpr; /* Number of expressions on the list */
char *zEName; /* Token associated with this expression */
struct {
u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */
- unsigned eEName :2; /* Meaning of zEName */
+ unsigned eEName :3; /* Meaning of zEName */
unsigned done :1; /* Indicates when processing is finished */
unsigned reusable :1; /* Constant expression is reusable */
unsigned bSorterRef :1; /* Defer evaluation until after sorting */
/*
** Allowed values for Expr.a.eEName
*/
-#define ENAME_NAME 0 /* The AS clause of a result set */
-#define ENAME_SPAN 1 /* Complete text of the result set expression */
-#define ENAME_TAB 2 /* "DB.TABLE.NAME" for the result set */
-#define ENAME_ROWID 3 /* "DB.TABLE._rowid_" for * expansion of rowid */
+#define ENAME_NAME 0 /* The AS clause of a result set */
+#define ENAME_SPAN 1 /* Complete text of the result set expression */
+#define ENAME_TAB 2 /* "DB.TABLE.NAME" for the result set */
+#define ENAME_ROWID 3 /* "DB.TABLE._rowid_" for * expansion of rowid */
+#define ENAME_EXCLUDE 4 /* *EXCLUDE column name */
+#define ENAME_REPLACE 5 /* *REPLACE column name */
+#define ENAME_RENAME 6 /* *RENAME column name */
/*
** An instance of this structure can hold a simple list of identifiers,