From 81f7b372700d7595f486d364a26304b052eda55a Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 16 Oct 2019 12:18:59 +0000 Subject: [PATCH 01/31] Initial experimental code for generated column support. Non-functional. FossilOrigin-Name: 11d472c1df707b8d03ec57d8fc582a34f5eb89a9d02a154a9871650c65065b45 --- manifest | 35 +++++++++++---------- manifest.uuid | 2 +- src/build.c | 73 ++++++++++++++++++++++++++++++++++++++++++++ src/delete.c | 7 +++-- src/expr.c | 34 +++++++++++++++------ src/parse.y | 6 ++++ src/pragma.c | 4 +-- src/resolve.c | 31 +++++++++++-------- src/select.c | 2 +- src/sqliteInt.h | 52 ++++++++++++++++++------------- src/update.c | 9 +++--- src/wherecode.c | 4 +-- tool/mkkeywordhash.c | 2 ++ 13 files changed, 190 insertions(+), 71 deletions(-) diff --git a/manifest b/manifest index 1876174cf9..d7670f50bb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Formatting\schange\son\sa\smulti-line\sconditional,\sfor\simproved\sclarity.\nNo\slogic\schanges. -D 2019-10-15T19:01:55.901 +C Initial\sexperimental\scode\sfor\sgenerated\scolumn\ssupport.\s\sNon-functional. +D 2019-10-16T12:18:59.297 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,15 +469,15 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c 13de2fdabbabcf2e2aaf6443a049fb851d9d3170136c08345468e158ceea3dc6 +F src/build.c 0ed5a7bb102a1972ce045b7a14753ed65bf62c7e32a44f162bfdce6f50bd7619 F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319 -F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf -F src/expr.c 4c2a0d00a0d7701811a463b9af2c63d10b0c5ee7b8bde249309184f82d27b5b0 +F src/delete.c fd10ac325c73bdf4d558530745d70df01fe6f7a0763553045adf42a62c303dc9 +F src/expr.c 6c2b2dc1d7eb9af9920e9f0a51f0fcc5f6bf0166ea88caa32175f3543f2290f1 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 6271fda51794b569d736eba4097d28f13080cd0c9eb66d5fcecb4b77336fae50 F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12 @@ -514,23 +514,23 @@ F src/os_win.c 035a813cbd17f355bdcad7ab894af214a9c13a1db8aeac902365350b98cd45a7 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 422fd8cfa59fb9173eff36a95878904a0eeb0dcc62ba49350acc8b1e51c4dc7b F src/pager.h 217921e81eb5fe455caa5cda96061959706bcdd29ddb57166198645ef7822ac3 -F src/parse.y 19c8b65c87a5bec5efcb7eaf44e3178d860bc77baab4b03d7b53b08369ac83bf +F src/parse.y 516984fb37a025a2034456924f9e395b12162026c84f81e13270acab519f49e4 F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 62714cbd1b7299a6e6a27a587b66b4fd3a836a84e1181e7f96f5c34a50917848 -F src/pragma.c b47bc7db02ab13d04c680aee424466b4e34f4ef5aa7b2e464876ec005806f98f +F src/pragma.c 941aad9029be6fc71fb3dd58db122710d3f8da0ee48bf2b3350364694d000c98 F src/pragma.h 40962d65b645bb3f08c1f4c456effd01c6e7f073f68ea25177e0c95e181cff75 F src/prepare.c 6049beb71385f017af6fc320d2c75a4e50b75e280c54232442b785fbb83df057 F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 -F src/resolve.c e021be0c1c4a2125fa38aabcd8dbb764bf5b2c889a948c30d3708430ec6ccd00 +F src/resolve.c 2160146697e6e0ba251b5a954e16f542b6e684fb4778cec2994094ab401ef996 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 -F src/select.c 7ef05eeb7f686f84dd1428cbdca280c898915bbf56e1ea97bd42ecc070af78d3 +F src/select.c ac9270006d5e1c283012fe116f36a8d496a49a296943f777176f61c0c903ea00 F src/shell.c.in d70bcf630c4073eaa994fa74be98886c781918e794cb8b562be8df10f018e274 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h 40f81bb57b0723403d5da77314d459f536ddd0f07d57434a94df35e790b6b268 +F src/sqliteInt.h dcef2c667f65742385e13847823b298fc75a8980ca572ed2bf0ff15b68a4ea32 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -592,7 +592,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c d3615f0cbe4db5949503bf5916f3cd4fa5de855d5b4ef560f3b6dd5629423a1e F src/treeview.c fddeb413159c3eeeaea3f496172f121cf3695606c461dc4e6dcee51417952df5 F src/trigger.c 845ccc08f60716c58aa28fe6470385c18ef8c4e1d88c93dcf449bc13d464eb2e -F src/update.c 7f05fad5e145248a00048aeb0bac78b8fdb4ed17216e14a6eb24c55596e87ee7 +F src/update.c 1ad2eb4006a06b13f5eadbbdebe0c4dc7e987428dfdeef18429f533d2dae8618 F src/upsert.c 710c91bb13e3c3fed5b6fe17cb13e09560bdd003ad8b8c51e6b16c80cfc48b10 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507 F src/util.c 10d910e04a4f3842042485e0df01a484f57f912c10b60b3a09ccddd5019bd138 @@ -613,7 +613,7 @@ F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a F src/walker.c d5a94907dcac990e31976be9dc769d17f6a806782593d6aec9d760ee01ec22cd F src/where.c 9f3f23efc45934e7b7ea6c0c1042420b73053e7c3264feef6faf9ce6fbd5df61 F src/whereInt.h 2c6bae136a7c0be6ff75dc36950d1968c67d005c8e51d7a9d77cb996bb4843d9 -F src/wherecode.c 57d034a0dbca9f86e1a691f74e469ed09ff49d04712b838fb68596b76a9af7d2 +F src/wherecode.c 39df666a7281d3153b9f9d2cb04321cbb7cc403623a2862a292cb074e1b4a203 F src/whereexpr.c 05c283d26aa9c3f5d1bf13a5f6a573b43295b9db280eff18e26f97d7d7f119b4 F src/window.c 064f251451c8e2a1c76b6269229d911a651e119c6a5f522b6eaebf8dc8714041 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1775,7 +1775,7 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439 F tool/mkautoconfamal.sh 422fc365358a2e92876ffc62971a0ff28ed472fc8bcf9de0df921c736fdeca5e F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3 -F tool/mkkeywordhash.c bc5bcc92ebcaf15345346be7cf2204b83ed649b5208234adb5e543c061209bbf +F tool/mkkeywordhash.c 8973d556c5ee984b510269623c316ce0767f61dbd789075a05f213f3a576d840 F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6a13ea F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21 @@ -1847,7 +1847,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P bc751fb64d5b08e5ca4c85cd1c6fbf09590fa9dad7e176ba373082ea373655b5 -R 3dc274e5f048c65fb3fe7dfe730dc64a +P 7248e3476511ecd317f54edcfe1e87443bfdcc1b10c89c7734eefcabafec6c0b +R 3d12505eaf33c3dd163aeb1612c4c830 +T *branch * generated-columns +T *sym-generated-columns * +T -sym-trunk * U drh -Z a66229c65bafcb1e69be0fef5ecdca35 +Z 84f42f4fd8439ebec34b72547b3c2d42 diff --git a/manifest.uuid b/manifest.uuid index 30f2e65a57..cd38124276 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7248e3476511ecd317f54edcfe1e87443bfdcc1b10c89c7734eefcabafec6c0b \ No newline at end of file +11d472c1df707b8d03ec57d8fc582a34f5eb89a9d02a154a9871650c65065b45 \ No newline at end of file diff --git a/src/build.c b/src/build.c index e4f8d5e3c6..7e1f3b40cf 100644 --- a/src/build.c +++ b/src/build.c @@ -888,6 +888,27 @@ i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){ return -1; } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS +/* +** Of the iCol-th column in table pTab, return the index of that column +** as stored on disk. Usually the return value is the same as the iCol +** input, however the return value may be less there are prior VIRTUAL +** columns. +** +** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro +*/ +i16 sqlite3ColumnOfTable(Table *pTab, i16 iCol){ + int i; + i16 n; + assert( iColnCol ); + if( pTab->nVCol==0 ) return iCol; + for(i=0, n=0; iaCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) n++; + } + return n; +} +#endif + /* ** Begin constructing a new table representation in memory. This is ** the first of several action routines that get called in response @@ -1520,6 +1541,47 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){ } } +/* Change the most recently parsed column to be a GENERATED ALWAYS AS +** column. +*/ +void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + u8 eType = COLFLAG_VIRTUAL; + Table *pTab = pParse->pNewTable; + Column *pCol; + if( IN_RENAME_OBJECT ){ + sqlite3RenameExprUnmap(pParse, pExpr); + } + if( pTab==0 ) goto generated_done; + pCol = &(pTab->aCol[pTab->nCol-1]); + if( pCol->pDflt ) goto generated_error; + if( pType ){ + if( pType->n==7 && sqlite3StrNICmp("virtual",pType->z,7)==0 ){ + /* no-op */ + }else if( pType->n==6 && sqlite3StrNICmp("stored",pType->z,6)==0 ){ + eType = COLFLAG_STORED; + }else{ + goto generated_error; + } + } + pTab->nVCol++; + pCol->colFlags |= eType; + pCol->pDflt = sqlite3ExprDup(pParse->db, pExpr, 0); + goto generated_done; + +generated_error: + sqlite3ErrorMsg(pParse, "bad GENERATED ALWAYS AS clause on column \"%s\"", + pCol->zName); +generated_done: + sqlite3ExprDelete(pParse->db, pExpr); +#else + /* Throw and error for the GENERATED ALWAYS AS clause if the + ** SQLITE_OMIT_GENERATED_COLUMNS compile-time option is used. */ + sqlite3ErrorMsg(pParse, "GENERATED ALWAYS AS not supported"); + sqlite3ExprDelete(pParse->db, pExpr); +#endif +} + /* ** This function returns the collation sequence for database native text ** encoding identified by the string zName, length nName. @@ -2114,6 +2176,17 @@ void sqlite3EndTable( sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck); } #endif /* !defined(SQLITE_OMIT_CHECK) */ +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( p->nVCol ){ + int ii; + for(ii=0; iinCol; ii++){ + if( (p->aCol[ii].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL))!=0 ){ + sqlite3ResolveSelfReference(pParse, p, NC_GenCol, + p->aCol[ii].pDflt, 0); + } + } + } +#endif /* Estimate the average row size for the table and for all implied indices */ estimateTableWidth(p); diff --git a/src/delete.c b/src/delete.c index e3a0abc2c0..271bdbd482 100644 --- a/src/delete.c +++ b/src/delete.c @@ -475,13 +475,13 @@ void sqlite3DeleteFrom( if( pPk ){ for(i=0; iaiColumn[i]>=0 ); - sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iTabCur, pPk->aiColumn[i], iPk+i); } iKey = iPk; }else{ iKey = ++pParse->nMem; - sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, -1, iKey); + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iTabCur, -1, iKey); } if( eOnePass!=ONEPASS_OFF ){ @@ -737,7 +737,8 @@ void sqlite3GenerateRowDelete( testcase( mask!=0xffffffff && iCol==31 ); testcase( mask!=0xffffffff && iCol==32 ); if( mask==0xffffffff || (iCol<=31 && (mask & MASKBIT32(iCol))!=0) ){ - sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+iCol+1); + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, iCol, + iOld+iCol+1); } } diff --git a/src/expr.c b/src/expr.c index 0e827482b2..fea7b0a18b 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3365,7 +3365,7 @@ void sqlite3ExprCodeLoadIndexColumn( sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut); pParse->iSelfTab = 0; }else{ - sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur, + sqlite3ExprCodeGetColumnOfTable(pParse, pIdx->pTable, iTabCur, iTabCol, regOut); } } @@ -3374,12 +3374,14 @@ void sqlite3ExprCodeLoadIndexColumn( ** Generate code to extract the value of the iCol-th column of a table. */ void sqlite3ExprCodeGetColumnOfTable( - Vdbe *v, /* The VDBE under construction */ + Parse *pParse, /* Parsing context */ Table *pTab, /* The table containing the value */ int iTabCur, /* The table cursor. Or the PK cursor for WITHOUT ROWID */ int iCol, /* Index of the column to extract */ int regOut /* Extract the value into this register */ ){ + Vdbe *v = pParse->pVdbe; + assert( v!=0 ); if( pTab==0 ){ sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut); return; @@ -3387,10 +3389,25 @@ void sqlite3ExprCodeGetColumnOfTable( if( iCol<0 || iCol==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut); }else{ - int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; - int x = iCol; - if( !HasRowid(pTab) && !IsVirtual(pTab) ){ + int op; + int x; + if( IsVirtual(pTab) ){ + op = OP_VColumn; + x = iCol; +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + }else if( pTab->aCol[iCol].colFlags & COLFLAG_VIRTUAL ){ + int savedSelfTab = pParse->iSelfTab; + pParse->iSelfTab = iTabCur+1; + sqlite3ExprCode(pParse, pTab->aCol[iCol].pDflt, iCol); + pParse->iSelfTab = savedSelfTab; + return; +#endif + }else if( !HasRowid(pTab) ){ x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol); + op = OP_Column; + }else{ + x = sqlite3ColumnOfTable(pTab,iCol); + op = OP_Column; } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); } @@ -3414,11 +3431,10 @@ int sqlite3ExprCodeGetColumn( int iReg, /* Store results here */ u8 p5 /* P5 value for OP_Column + FLAGS */ ){ - Vdbe *v = pParse->pVdbe; - assert( v!=0 ); - sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg); + assert( pParse->pVdbe!=0 ); + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iTable, iColumn, iReg); if( p5 ){ - sqlite3VdbeChangeP5(v, p5); + sqlite3VdbeChangeP5(pParse->pVdbe, p5); } return iReg; } diff --git a/src/parse.y b/src/parse.y index 7d31dda405..028a8c77dd 100644 --- a/src/parse.y +++ b/src/parse.y @@ -347,6 +347,12 @@ ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R). {sqlite3CreateForeignKey(pParse,0,&T,TA,R);} ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);} ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);} +ccons ::= GENERATED ALWAYS AS generated. +ccons ::= AS generated. +generated ::= LP expr(E) RP. + {sqlite3AddGenerated(pParse,E,0);} +generated ::= LP expr(E) RP ID(TYPE). + {sqlite3AddGenerated(pParse,E,&TYPE);} // The optional AUTOINCREMENT keyword %type autoinc {int} diff --git a/src/pragma.c b/src/pragma.c index 858e314a1e..4c715019e7 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1398,7 +1398,7 @@ void sqlite3Pragma( ** this case. */ for(j=0; jnCol; j++){ int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom; - sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j); + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, 0, iCol, regRow+j); sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); } @@ -1586,7 +1586,7 @@ void sqlite3Pragma( int jmp2; if( j==pTab->iPKey ) continue; if( pTab->aCol[j].notNull==0 ) continue; - sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, j, 3); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, diff --git a/src/resolve.c b/src/resolve.c index e66dc18eb8..657746842d 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -414,7 +414,7 @@ static int lookupName( if( cnt==0 && cntTab==1 && pMatch - && (pNC->ncFlags & NC_IdxExpr)==0 + && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0 && sqlite3IsRowid(zCol) && VisibleRowid(pMatch->pTab) ){ @@ -625,12 +625,15 @@ static void notValid( const char *zMsg, /* Type of error */ int validMask /* Set of contexts for which prohibited */ ){ - assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr))==0 ); + assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol))==0 ); if( (pNC->ncFlags & validMask)!=0 ){ const char *zIn = "partial index WHERE clauses"; if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions"; #ifndef SQLITE_OMIT_CHECK else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints"; +#endif +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + else if( pNC->ncFlags & NC_GenCol ) zIn = "GENERATED ALWAYS AS columns"; #endif sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn); } @@ -723,7 +726,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ zColumn = pExpr->u.zToken; }else{ Expr *pLeft = pExpr->pLeft; - notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr); + notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr|NC_GenCol); pRight = pExpr->pRight; if( pRight->op==TK_ID ){ zDb = 0; @@ -820,7 +823,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ ** sqlite_version() that might change over time cannot be used ** in an index. */ notValid(pParse, pNC, "non-deterministic functions", - NC_IdxExpr|NC_PartIdx); + NC_IdxExpr|NC_PartIdx|NC_GenCol); } if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 && pParse->nested==0 @@ -964,7 +967,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_IN ); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ int nRef = pNC->nRef; - notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr); + notValid(pParse, pNC, "subqueries", + NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol); sqlite3WalkSelect(pWalker, pExpr->x.pSelect); assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ @@ -975,7 +979,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ break; } case TK_VARIABLE: { - notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr); + notValid(pParse, pNC, "parameters", + NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol); break; } case TK_IS: @@ -1788,6 +1793,7 @@ void sqlite3ResolveSelectNames( ** (2) WHERE clauses on partial indices ** (3) Expressions in indexes on expressions ** (4) Expression arguments to VACUUM INTO. +** (5) GENERATED ALWAYS as expressions ** ** In all cases except (4), the Expr.iTable value for Expr.op==TK_COLUMN ** nodes of the expression is set to -1 and the Expr.iColumn value is @@ -1796,18 +1802,19 @@ void sqlite3ResolveSelectNames( ** Any errors cause an error message to be set in pParse. */ int sqlite3ResolveSelfReference( - Parse *pParse, /* Parsing context */ - Table *pTab, /* The table being referenced, or NULL */ - int type, /* NC_IsCheck or NC_PartIdx or NC_IdxExpr, or 0 */ - Expr *pExpr, /* Expression to resolve. May be NULL. */ - ExprList *pList /* Expression list to resolve. May be NULL. */ + Parse *pParse, /* Parsing context */ + Table *pTab, /* The table being referenced, or NULL */ + int type, /* NC_IsCheck, NC_PartIdx, NC_IdxExpr, NC_GenCol, or 0 */ + Expr *pExpr, /* Expression to resolve. May be NULL. */ + ExprList *pList /* Expression list to resolve. May be NULL. */ ){ SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ NameContext sNC; /* Name context for pParse->pNewTable */ int rc; assert( type==0 || pTab!=0 ); - assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr || pTab==0 ); + assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr + || type==NC_GenCol || pTab==0 ); memset(&sNC, 0, sizeof(sNC)); memset(&sSrc, 0, sizeof(sSrc)); if( pTab ){ diff --git a/src/select.c b/src/select.c index a5377a2c20..f63ca06f4a 100644 --- a/src/select.c +++ b/src/select.c @@ -6417,7 +6417,7 @@ int sqlite3Select( struct AggInfo_col *pCol = &sAggInfo.aCol[i]; if( pCol->iSorterColumn>=j ){ int r1 = j + regBase; - sqlite3ExprCodeGetColumnOfTable(v, + sqlite3ExprCodeGetColumnOfTable(pParse, pCol->pTab, pCol->iTable, pCol->iColumn, r1); j++; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 44a82223e6..e16a5066c9 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1823,7 +1823,7 @@ struct Module { */ struct Column { char *zName; /* Name of this column, \000, then the type */ - Expr *pDflt; /* Default value of this column */ + Expr *pDflt; /* Default value or GENERATED ALWAYS AS value */ char *zColl; /* Collating sequence. If NULL, use the default */ u8 notNull; /* An OE_ code for handling a NOT NULL constraint */ char affinity; /* One of the SQLITE_AFF_... values */ @@ -1833,11 +1833,13 @@ struct Column { /* Allowed values for Column.colFlags: */ -#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */ -#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */ -#define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */ -#define COLFLAG_UNIQUE 0x0008 /* Column def contains "UNIQUE" or "PK" */ +#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */ +#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */ +#define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */ +#define COLFLAG_UNIQUE 0x0008 /* Column def contains "UNIQUE" or "PK" */ #define COLFLAG_SORTERREF 0x0010 /* Use sorter-refs with this column */ +#define COLFLAG_VIRTUAL 0x0020 /* GENERATED ALWAYS AS ... VIRTUAL */ +#define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */ /* ** A "Collating Sequence" is defined by an instance of the following @@ -1977,6 +1979,7 @@ struct Table { u32 tabFlags; /* Mask of TF_* values */ i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */ i16 nCol; /* Number of columns in this table */ + i16 nVCol; /* Number of virtual columns */ LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ #ifdef SQLITE_ENABLE_COSTMULT @@ -2808,21 +2811,22 @@ struct NameContext { ** NC_HasWin == EP_Win ** */ -#define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */ -#define NC_PartIdx 0x0002 /* True if resolving a partial index WHERE */ -#define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */ -#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */ -#define NC_HasAgg 0x0010 /* One or more aggregate functions seen */ -#define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */ -#define NC_VarSelect 0x0040 /* A correlated subquery has been seen */ -#define NC_UEList 0x0080 /* True if uNC.pEList is used */ -#define NC_UAggInfo 0x0100 /* True if uNC.pAggInfo is used */ -#define NC_UUpsert 0x0200 /* True if uNC.pUpsert is used */ -#define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ -#define NC_Complex 0x2000 /* True if a function or subquery seen */ -#define NC_AllowWin 0x4000 /* Window functions are allowed here */ -#define NC_HasWin 0x8000 /* One or more window functions seen */ -#define NC_IsDDL 0x10000 /* Resolving names in a CREATE statement */ +#define NC_AllowAgg 0x00001 /* Aggregate functions are allowed here */ +#define NC_PartIdx 0x00002 /* True if resolving a partial index WHERE */ +#define NC_IsCheck 0x00004 /* True if resolving a CHECK constraint */ +#define NC_InAggFunc 0x00008 /* True if analyzing arguments to an agg func */ +#define NC_HasAgg 0x00010 /* One or more aggregate functions seen */ +#define NC_IdxExpr 0x00020 /* True if resolving columns of CREATE INDEX */ +#define NC_VarSelect 0x00040 /* A correlated subquery has been seen */ +#define NC_UEList 0x00080 /* True if uNC.pEList is used */ +#define NC_UAggInfo 0x00100 /* True if uNC.pAggInfo is used */ +#define NC_UUpsert 0x00200 /* True if uNC.pUpsert is used */ +#define NC_MinMaxAgg 0x01000 /* min/max aggregates seen. See note above */ +#define NC_Complex 0x02000 /* True if a function or subquery seen */ +#define NC_AllowWin 0x04000 /* Window functions are allowed here */ +#define NC_HasWin 0x08000 /* One or more window functions seen */ +#define NC_IsDDL 0x10000 /* Resolving names in a CREATE statement */ +#define NC_GenCol 0x20000 /* True for a GENERATED ALWAYS AS clause */ /* ** An instance of the following object describes a single ON CONFLICT @@ -3938,6 +3942,11 @@ Table *sqlite3ResultSetOfSelect(Parse*,Select*,char); void sqlite3OpenMasterTable(Parse *, int); Index *sqlite3PrimaryKeyIndex(Table*); i16 sqlite3ColumnOfIndex(Index*, i16); +#ifdef SQLITE_OMIT_GENERATED_COLUMNS +# define sqlite3ColumnOfTable(T,X) (X) /* No-op pass-through */ +#else + i16 sqlite3ColumnOfTable(Table*, i16); +#endif void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); #if SQLITE_ENABLE_HIDDEN_COLUMNS void sqlite3ColumnPropertiesFromName(Table*, Column*); @@ -3950,6 +3959,7 @@ void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); void sqlite3AddCheckConstraint(Parse*, Expr*); void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*); void sqlite3AddCollateType(Parse*, Token*); +void sqlite3AddGenerated(Parse*,Expr*,Token*); void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*); int sqlite3ParseUri(const char*,const char*,unsigned int*, sqlite3_vfs**,char**,char **); @@ -4053,7 +4063,7 @@ int sqlite3WhereOkOnePass(WhereInfo*, int*); #define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */ void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); -void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); +void sqlite3ExprCodeGetColumnOfTable(Parse*, Table*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprCode(Parse*, Expr*, int); void sqlite3ExprCodeCopy(Parse*, Expr*, int); diff --git a/src/update.c b/src/update.c index 458550b95d..9826ae2707 100644 --- a/src/update.c +++ b/src/update.c @@ -542,7 +542,8 @@ void sqlite3Update( ** is not required) and leave the PK fields in the array of registers. */ for(i=0; iaiColumn[i]>=0 ); - sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,pPk->aiColumn[i],iPk+i); + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, + pPk->aiColumn[i], iPk+i); } if( eOnePass ){ if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen); @@ -628,7 +629,7 @@ void sqlite3Update( || (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){ testcase( oldmask!=0xffffffff && i==31 ); - sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regOld+i); + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, regOld+i); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i); } @@ -669,7 +670,7 @@ void sqlite3Update( */ testcase( i==31 ); testcase( i==32 ); - sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i); + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, regNew+i); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); } @@ -709,7 +710,7 @@ void sqlite3Update( */ for(i=0; inCol; i++){ if( aXRef[i]<0 && i!=pTab->iPKey ){ - sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i); + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, regNew+i); } } } diff --git a/src/wherecode.c b/src/wherecode.c index e40e3f2704..39b9040db7 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -2072,7 +2072,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); if( HasRowid(pTab) ){ - sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, regRowid); + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iCur, -1, regRowid); jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, regRowid, iSet); VdbeCoverage(v); @@ -2086,7 +2086,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( r = sqlite3GetTempRange(pParse, nPk); for(iPk=0; iPkaiColumn[iPk]; - sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, r+iPk); + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iCur, iCol,r+iPk); } /* Check if the temp table already contains this key. If so, diff --git a/tool/mkkeywordhash.c b/tool/mkkeywordhash.c index 77bc4ac5c0..b5784fdecd 100644 --- a/tool/mkkeywordhash.c +++ b/tool/mkkeywordhash.c @@ -164,6 +164,7 @@ static Keyword aKeywordTable[] = { { "AFTER", "TK_AFTER", TRIGGER }, { "ALL", "TK_ALL", ALWAYS }, { "ALTER", "TK_ALTER", ALTER }, + { "ALWAYS", "TK_ALWAYS", ALWAYS }, { "ANALYZE", "TK_ANALYZE", ANALYZE }, { "AND", "TK_AND", ALWAYS }, { "AS", "TK_AS", ALWAYS }, @@ -216,6 +217,7 @@ static Keyword aKeywordTable[] = { { "FOREIGN", "TK_FOREIGN", FKEY }, { "FROM", "TK_FROM", ALWAYS }, { "FULL", "TK_JOIN_KW", ALWAYS }, + { "GENERATED", "TK_GENERATED", ALWAYS }, { "GLOB", "TK_LIKE_KW", ALWAYS }, { "GROUP", "TK_GROUP", ALWAYS }, { "GROUPS", "TK_GROUPS", WINDOWFUNC }, From 7e508f1ee2d671976fd1dbe4a8fdbc840ba39b97 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 16 Oct 2019 19:31:46 +0000 Subject: [PATCH 02/31] Simple INSERT and SELECT operations working with VIRTUAL columns. FossilOrigin-Name: 7f9f90b1b885fa9905b296f2e0fcc9b2341019b42fc839722a93cf60e49a9252 --- manifest | 23 ++++++++++------------- manifest.uuid | 2 +- src/expr.c | 2 +- src/insert.c | 21 +++++++++++++++++---- src/parse.y | 6 ++---- src/pragma.c | 2 +- src/sqliteInt.h | 1 + 7 files changed, 33 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index d7670f50bb..f1dc653477 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Initial\sexperimental\scode\sfor\sgenerated\scolumn\ssupport.\s\sNon-functional. -D 2019-10-16T12:18:59.297 +C Simple\sINSERT\sand\sSELECT\soperations\sworking\swith\sVIRTUAL\scolumns. +D 2019-10-16T19:31:46.693 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -477,7 +477,7 @@ F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319 F src/delete.c fd10ac325c73bdf4d558530745d70df01fe6f7a0763553045adf42a62c303dc9 -F src/expr.c 6c2b2dc1d7eb9af9920e9f0a51f0fcc5f6bf0166ea88caa32175f3543f2290f1 +F src/expr.c 5f2e2678c17325d41fbcb0e76c40d50f4ac5ddbd57bf6a6e62d7db2e5f899654 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 6271fda51794b569d736eba4097d28f13080cd0c9eb66d5fcecb4b77336fae50 F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 40557ebd69f4115e7a273f9304a8ab637a47ce44f3c6923396928f023967b5e8 +F src/insert.c de9dea8081c500156d8c2e0079a123d56ef736d283ec7806f401886dd55c5ab7 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -514,11 +514,11 @@ F src/os_win.c 035a813cbd17f355bdcad7ab894af214a9c13a1db8aeac902365350b98cd45a7 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 422fd8cfa59fb9173eff36a95878904a0eeb0dcc62ba49350acc8b1e51c4dc7b F src/pager.h 217921e81eb5fe455caa5cda96061959706bcdd29ddb57166198645ef7822ac3 -F src/parse.y 516984fb37a025a2034456924f9e395b12162026c84f81e13270acab519f49e4 +F src/parse.y bc453ce808316facd191413bfa4ec6730a1d693b98fd8be5addef8fbfd62bb7b F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 62714cbd1b7299a6e6a27a587b66b4fd3a836a84e1181e7f96f5c34a50917848 -F src/pragma.c 941aad9029be6fc71fb3dd58db122710d3f8da0ee48bf2b3350364694d000c98 +F src/pragma.c a9511633bc0ee6c67b9ed244d7b1c0770c71e5211d94c8c97d631974166d59b4 F src/pragma.h 40962d65b645bb3f08c1f4c456effd01c6e7f073f68ea25177e0c95e181cff75 F src/prepare.c 6049beb71385f017af6fc320d2c75a4e50b75e280c54232442b785fbb83df057 F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4 @@ -530,7 +530,7 @@ F src/shell.c.in d70bcf630c4073eaa994fa74be98886c781918e794cb8b562be8df10f018e27 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h dcef2c667f65742385e13847823b298fc75a8980ca572ed2bf0ff15b68a4ea32 +F src/sqliteInt.h 47d43085f2165aa4ddb87f8a0341937104dfd94bcce0445d296eac8e59ab25e2 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -1847,10 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7248e3476511ecd317f54edcfe1e87443bfdcc1b10c89c7734eefcabafec6c0b -R 3d12505eaf33c3dd163aeb1612c4c830 -T *branch * generated-columns -T *sym-generated-columns * -T -sym-trunk * +P 11d472c1df707b8d03ec57d8fc582a34f5eb89a9d02a154a9871650c65065b45 +R 899dceb15c24c2e2f3f3f41aea0d96fa U drh -Z 84f42f4fd8439ebec34b72547b3c2d42 +Z 2fd76d80cb2634f812acd88fb56b891f diff --git a/manifest.uuid b/manifest.uuid index cd38124276..43616447f9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -11d472c1df707b8d03ec57d8fc582a34f5eb89a9d02a154a9871650c65065b45 \ No newline at end of file +7f9f90b1b885fa9905b296f2e0fcc9b2341019b42fc839722a93cf60e49a9252 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index fea7b0a18b..e02e146582 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3398,7 +3398,7 @@ void sqlite3ExprCodeGetColumnOfTable( }else if( pTab->aCol[iCol].colFlags & COLFLAG_VIRTUAL ){ int savedSelfTab = pParse->iSelfTab; pParse->iSelfTab = iTabCur+1; - sqlite3ExprCode(pParse, pTab->aCol[iCol].pDflt, iCol); + sqlite3ExprCode(pParse, pTab->aCol[iCol].pDflt, regOut); pParse->iSelfTab = savedSelfTab; return; #endif diff --git a/src/insert.c b/src/insert.c index d9078b89db..f2ed9d9a32 100644 --- a/src/insert.c +++ b/src/insert.c @@ -37,7 +37,8 @@ void sqlite3OpenTable( sqlite3TableLock(pParse, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName); if( HasRowid(pTab) ){ - sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nCol); + sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, + pTab->nCol - pTab->nVCol); VdbeComment((v, "%s", pTab->zName)); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); @@ -673,6 +674,14 @@ void sqlite3Insert( if( j==pTab->iPKey ){ ipkColumn = i; assert( !withoutRowid ); } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ + sqlite3ErrorMsg(pParse, + "cannot INSERT into generated column \"%s\"", + pTab->aCol[j].zName); + goto insert_cleanup; + } +#endif break; } } @@ -788,7 +797,7 @@ void sqlite3Insert( ** of columns to be inserted into the table. */ for(i=0; inCol; i++){ - nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0); + if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ) nHidden++; } if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){ sqlite3ErrorMsg(pParse, @@ -1006,9 +1015,12 @@ void sqlite3Insert( continue; } if( pColumn==0 ){ - if( IsHiddenColumn(&pTab->aCol[i]) ){ + if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ){ j = -1; nHidden++; + if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ + continue; + } }else{ j = i - nHidden; } @@ -1862,7 +1874,8 @@ void sqlite3GenerateConstraintChecks( /* Generate the table record */ if( HasRowid(pTab) ){ int regRec = aRegIdx[ix]; - sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData+1, pTab->nCol, regRec); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData+1, + pTab->nCol-pTab->nVCol, regRec); sqlite3SetMakeRecordP5(v, pTab); if( !bAffinityDone ){ sqlite3TableAffinity(v, pTab, 0); diff --git a/src/parse.y b/src/parse.y index 028a8c77dd..b38304aa7c 100644 --- a/src/parse.y +++ b/src/parse.y @@ -349,10 +349,8 @@ ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);} ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);} ccons ::= GENERATED ALWAYS AS generated. ccons ::= AS generated. -generated ::= LP expr(E) RP. - {sqlite3AddGenerated(pParse,E,0);} -generated ::= LP expr(E) RP ID(TYPE). - {sqlite3AddGenerated(pParse,E,&TYPE);} +generated ::= LP expr(E) RP. {sqlite3AddGenerated(pParse,E,0);} +generated ::= LP expr(E) RP ID(TYPE). {sqlite3AddGenerated(pParse,E,&TYPE);} // The optional AUTOINCREMENT keyword %type autoinc {int} diff --git a/src/pragma.c b/src/pragma.c index 4c715019e7..652810eae2 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1577,7 +1577,7 @@ void sqlite3Pragma( loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); if( !isQuick ){ /* Sanity check on record header decoding */ - sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-1, 3); + sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-pTab->nVCol-1,3); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); } /* Verify that all NOT NULL columns really are NOT NULL */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e16a5066c9..94d7107a08 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1840,6 +1840,7 @@ struct Column { #define COLFLAG_SORTERREF 0x0010 /* Use sorter-refs with this column */ #define COLFLAG_VIRTUAL 0x0020 /* GENERATED ALWAYS AS ... VIRTUAL */ #define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */ +#define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */ /* ** A "Collating Sequence" is defined by an instance of the following From c27ea2ae8df4207e6b2479b46904c73d7cd1775f Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 16 Oct 2019 20:05:56 +0000 Subject: [PATCH 03/31] ALTER TABLE is able to add a VIRTUAL column. FossilOrigin-Name: 120c6b78cb51532f783014605f1107d40b2e4f54e3852fb1f8f167d0c0b78c69 --- manifest | 18 ++++++------ manifest.uuid | 2 +- src/alter.c | 73 +++++++++++++++++++++++++------------------------ src/build.c | 2 +- src/insert.c | 6 ++-- src/sqliteInt.h | 1 + 6 files changed, 54 insertions(+), 48 deletions(-) diff --git a/manifest b/manifest index f1dc653477..991a0bbbff 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Simple\sINSERT\sand\sSELECT\soperations\sworking\swith\sVIRTUAL\scolumns. -D 2019-10-16T19:31:46.693 +C ALTER\sTABLE\sis\sable\sto\sadd\sa\sVIRTUAL\scolumn. +D 2019-10-16T20:05:56.905 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -459,7 +459,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c 5773b28684a001dcab45adcefa3cbf5e846335c0c8fee0da8a3770cb0123bba8 +F src/alter.c 8a4317e2b322d4da9489cf2aa1d513a3a6f3e4863552dd5e59d08cdaca73c487 F src/analyze.c 481d9cf34a3c70631ef5c416be70033e8d4cd85eb5ad1b37286aed8b0e29e889 F src/attach.c 3ca19504849c2d9be10fc5899d6811f9d6e848665d1a41ffb53df0cd6e7c13ed F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c 0ed5a7bb102a1972ce045b7a14753ed65bf62c7e32a44f162bfdce6f50bd7619 +F src/build.c 6cb40a36b3ec6a4b2dc36e0bd53e42ad448700c48b419569eae711cde4b175d3 F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c de9dea8081c500156d8c2e0079a123d56ef736d283ec7806f401886dd55c5ab7 +F src/insert.c c54ef99a0c47788a3cf2ace9ef9717b137484569e4c04bd940fc5222a6b3c209 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -530,7 +530,7 @@ F src/shell.c.in d70bcf630c4073eaa994fa74be98886c781918e794cb8b562be8df10f018e27 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h 47d43085f2165aa4ddb87f8a0341937104dfd94bcce0445d296eac8e59ab25e2 +F src/sqliteInt.h 6418b27039289b0274077c0f4f54b82c3150881b64dddb7d128786b55ec09920 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 11d472c1df707b8d03ec57d8fc582a34f5eb89a9d02a154a9871650c65065b45 -R 899dceb15c24c2e2f3f3f41aea0d96fa +P 7f9f90b1b885fa9905b296f2e0fcc9b2341019b42fc839722a93cf60e49a9252 +R 8a88337d2c1f89903f9ecf943d42ac46 U drh -Z 2fd76d80cb2634f812acd88fb56b891f +Z e34cdc64b33126ce9923adb3fcc6f90a diff --git a/manifest.uuid b/manifest.uuid index 43616447f9..3dd4dbb534 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7f9f90b1b885fa9905b296f2e0fcc9b2341019b42fc839722a93cf60e49a9252 \ No newline at end of file +120c6b78cb51532f783014605f1107d40b2e4f54e3852fb1f8f167d0c0b78c69 \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index 9d02d3835a..f8cada0e34 100644 --- a/src/alter.c +++ b/src/alter.c @@ -298,14 +298,6 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ } #endif - /* If the default value for the new column was specified with a - ** literal NULL, then set pDflt to 0. This simplifies checking - ** for an SQL NULL default below. - */ - assert( pDflt==0 || pDflt->op==TK_SPAN ); - if( pDflt && pDflt->pLeft->op==TK_NULL ){ - pDflt = 0; - } /* Check that the new column is not specified as PRIMARY KEY or UNIQUE. ** If there is a NOT NULL constraint, then the default value for the @@ -319,35 +311,46 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column"); return; } - if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){ - sqlite3ErrorMsg(pParse, - "Cannot add a REFERENCES column with non-NULL default value"); - return; - } - if( pCol->notNull && !pDflt ){ - sqlite3ErrorMsg(pParse, - "Cannot add a NOT NULL column with default value NULL"); - return; + if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){ + /* If the default value for the new column was specified with a + ** literal NULL, then set pDflt to 0. This simplifies checking + ** for an SQL NULL default below. + */ + assert( pDflt==0 || pDflt->op==TK_SPAN ); + if( pDflt && pDflt->pLeft->op==TK_NULL ){ + pDflt = 0; + } + if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){ + sqlite3ErrorMsg(pParse, + "Cannot add a REFERENCES column with non-NULL default value"); + return; + } + if( pCol->notNull && !pDflt ){ + sqlite3ErrorMsg(pParse, + "Cannot add a NOT NULL column with default value NULL"); + return; + } + + /* Ensure the default expression is something that sqlite3ValueFromExpr() + ** can handle (i.e. not CURRENT_TIME etc.) + */ + if( pDflt ){ + sqlite3_value *pVal = 0; + int rc; + rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal); + assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); + if( rc!=SQLITE_OK ){ + assert( db->mallocFailed == 1 ); + return; + } + if( !pVal ){ + sqlite3ErrorMsg(pParse,"Cannot add a column with non-constant default"); + return; + } + sqlite3ValueFree(pVal); + } } - /* Ensure the default expression is something that sqlite3ValueFromExpr() - ** can handle (i.e. not CURRENT_TIME etc.) - */ - if( pDflt ){ - sqlite3_value *pVal = 0; - int rc; - rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal); - assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); - if( rc!=SQLITE_OK ){ - assert( db->mallocFailed == 1 ); - return; - } - if( !pVal ){ - sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default"); - return; - } - sqlite3ValueFree(pVal); - } /* Modify the CREATE TABLE statement. */ zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); diff --git a/src/build.c b/src/build.c index 7e1f3b40cf..897e9183eb 100644 --- a/src/build.c +++ b/src/build.c @@ -1570,7 +1570,7 @@ void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ goto generated_done; generated_error: - sqlite3ErrorMsg(pParse, "bad GENERATED ALWAYS AS clause on column \"%s\"", + sqlite3ErrorMsg(pParse, "incorrect GENERATED ALWAYS AS on column \"%s\"", pCol->zName); generated_done: sqlite3ExprDelete(pParse->db, pExpr); diff --git a/src/insert.c b/src/insert.c index f2ed9d9a32..22c48d7f3c 100644 --- a/src/insert.c +++ b/src/insert.c @@ -532,6 +532,7 @@ void sqlite3Insert( u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */ u8 bIdListInOrder; /* True if IDLIST is in table order */ ExprList *pList = 0; /* List of VALUES() to be inserted */ + int iRegStore; /* Register in which to store next column */ /* Register allocations */ int regFromSelect = 0;/* Base register for data coming from SELECT */ @@ -1003,8 +1004,8 @@ void sqlite3Insert( ** with the first column. */ nHidden = 0; - for(i=0; inCol; i++){ - int iRegStore = regRowid+1+i; + iRegStore = regRowid+1; + for(i=0; inCol; i++, iRegStore++){ if( i==pTab->iPKey ){ /* The value of the INTEGER PRIMARY KEY column is always a NULL. ** Whenever this column is read, the rowid will be substituted @@ -1019,6 +1020,7 @@ void sqlite3Insert( j = -1; nHidden++; if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ + iRegStore--; continue; } }else{ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 94d7107a08..eb815a79e0 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1840,6 +1840,7 @@ struct Column { #define COLFLAG_SORTERREF 0x0010 /* Use sorter-refs with this column */ #define COLFLAG_VIRTUAL 0x0020 /* GENERATED ALWAYS AS ... VIRTUAL */ #define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */ +#define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */ #define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */ /* From ab45fc041389b937cf82c20bec231905105f829d Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 16 Oct 2019 22:01:56 +0000 Subject: [PATCH 04/31] INSERT with named columns for a table with generated columns. FossilOrigin-Name: 64db39f92d68d1b9f23e48af35e16b969c38b58041fbe900066eeb3ddb291cef --- manifest | 16 ++++++------- manifest.uuid | 2 +- src/expr.c | 17 +++++++++----- src/insert.c | 60 ++++++++++++++++++++++++++++++------------------- src/sqliteInt.h | 1 + 5 files changed, 59 insertions(+), 37 deletions(-) diff --git a/manifest b/manifest index 991a0bbbff..45942a0a1a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C ALTER\sTABLE\sis\sable\sto\sadd\sa\sVIRTUAL\scolumn. -D 2019-10-16T20:05:56.905 +C INSERT\swith\snamed\scolumns\sfor\sa\stable\swith\sgenerated\scolumns. +D 2019-10-16T22:01:56.225 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -477,7 +477,7 @@ F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319 F src/delete.c fd10ac325c73bdf4d558530745d70df01fe6f7a0763553045adf42a62c303dc9 -F src/expr.c 5f2e2678c17325d41fbcb0e76c40d50f4ac5ddbd57bf6a6e62d7db2e5f899654 +F src/expr.c 61d9043b1b9b82d72c919bcf5801a885a0ee7e41bf3e5ce3021b206a5706a949 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 6271fda51794b569d736eba4097d28f13080cd0c9eb66d5fcecb4b77336fae50 F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c c54ef99a0c47788a3cf2ace9ef9717b137484569e4c04bd940fc5222a6b3c209 +F src/insert.c 9dabd02b24946f4c38ae7ef566d65abc16476f9d26b3a630261f91e09c726722 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -530,7 +530,7 @@ F src/shell.c.in d70bcf630c4073eaa994fa74be98886c781918e794cb8b562be8df10f018e27 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h 6418b27039289b0274077c0f4f54b82c3150881b64dddb7d128786b55ec09920 +F src/sqliteInt.h ecade7aec917068cbbc96505eed645419e07799d91052926d418dd256d60b72d F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7f9f90b1b885fa9905b296f2e0fcc9b2341019b42fc839722a93cf60e49a9252 -R 8a88337d2c1f89903f9ecf943d42ac46 +P 120c6b78cb51532f783014605f1107d40b2e4f54e3852fb1f8f167d0c0b78c69 +R 69bb3625e06cb31ab7b6bfff123323c6 U drh -Z e34cdc64b33126ce9923adb3fcc6f90a +Z 504e145f33a96cfe775ae86c4e357f58 diff --git a/manifest.uuid b/manifest.uuid index 3dd4dbb534..927a0182f2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -120c6b78cb51532f783014605f1107d40b2e4f54e3852fb1f8f167d0c0b78c69 \ No newline at end of file +64db39f92d68d1b9f23e48af35e16b969c38b58041fbe900066eeb3ddb291cef \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index e02e146582..c21006b115 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3381,6 +3381,7 @@ void sqlite3ExprCodeGetColumnOfTable( int regOut /* Extract the value into this register */ ){ Vdbe *v = pParse->pVdbe; + Column *pCol; assert( v!=0 ); if( pTab==0 ){ sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut); @@ -3395,11 +3396,17 @@ void sqlite3ExprCodeGetColumnOfTable( op = OP_VColumn; x = iCol; #ifndef SQLITE_OMIT_GENERATED_COLUMNS - }else if( pTab->aCol[iCol].colFlags & COLFLAG_VIRTUAL ){ - int savedSelfTab = pParse->iSelfTab; - pParse->iSelfTab = iTabCur+1; - sqlite3ExprCode(pParse, pTab->aCol[iCol].pDflt, regOut); - pParse->iSelfTab = savedSelfTab; + }else if( (pCol = &pTab->aCol[iCol])->colFlags & COLFLAG_VIRTUAL ){ + if( pCol->colFlags & COLFLAG_BUSY ){ + sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pCol->zName); + }else{ + int savedSelfTab = pParse->iSelfTab; + pCol->colFlags |= COLFLAG_BUSY; + pParse->iSelfTab = iTabCur+1; + sqlite3ExprCode(pParse, pTab->aCol[iCol].pDflt, regOut); + pParse->iSelfTab = savedSelfTab; + pCol->colFlags &= ~COLFLAG_BUSY; + } return; #endif }else if( !HasRowid(pTab) ){ diff --git a/src/insert.c b/src/insert.c index 22c48d7f3c..20b5d9a91c 100644 --- a/src/insert.c +++ b/src/insert.c @@ -130,7 +130,7 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){ ** 'E' REAL */ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ - int i; + int i, j; char *zColAff = pTab->zColAff; if( zColAff==0 ){ sqlite3 *db = sqlite3VdbeDb(v); @@ -140,13 +140,15 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ return; } - for(i=0; inCol; i++){ + for(i=j=0; inCol; i++){ assert( pTab->aCol[i].affinity!=0 ); - zColAff[i] = pTab->aCol[i].affinity; + if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ + zColAff[j++] = pTab->aCol[i].affinity; + } } do{ - zColAff[i--] = 0; - }while( i>=0 && zColAff[i]<=SQLITE_AFF_BLOB ); + zColAff[j--] = 0; + }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB ); pTab->zColAff = zColAff; } assert( zColAff!=0 ); @@ -1006,6 +1008,9 @@ void sqlite3Insert( nHidden = 0; iRegStore = regRowid+1; for(i=0; inCol; i++, iRegStore++){ + int k; + assert( i>=nHidden ); + assert( iRegStore==sqlite3ColumnOfTable(pTab,i)+regRowid+1 ); if( i==pTab->iPKey ){ /* The value of the INTEGER PRIMARY KEY column is always a NULL. ** Whenever this column is read, the rowid will be substituted @@ -1015,32 +1020,41 @@ void sqlite3Insert( sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); continue; } - if( pColumn==0 ){ - if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ){ - j = -1; - nHidden++; - if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ - iRegStore--; - continue; - } + if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ){ + nHidden++; + if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ + /* Virtual columns are no stored */ + iRegStore--; }else{ - j = i - nHidden; - } - }else{ - for(j=0; jnId; j++){ - if( pColumn->a[j].idx==i ) break; + /* Hidden and stored columns get the default value */ + sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); } + continue; } - if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){ + if( pColumn ){ + for(j=0; jnId && pColumn->a[j].idx!=i; j++){} + if( j>=pColumn->nId ){ + /* A column not named in the insert column list gets its + ** default value */ + sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); + continue; + } + k = j; + }else if( nColumn==0 ){ sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); - }else if( useTempTable ){ - sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore); + continue; + }else{ + k = i - nHidden; + } + + if( useTempTable ){ + sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore); }else if( pSelect ){ if( regFromSelect!=regData ){ - sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore); + sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore); } }else{ - sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore); + sqlite3ExprCode(pParse, pList->a[k].pExpr, iRegStore); } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index eb815a79e0..8455155ae0 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1840,6 +1840,7 @@ struct Column { #define COLFLAG_SORTERREF 0x0010 /* Use sorter-refs with this column */ #define COLFLAG_VIRTUAL 0x0020 /* GENERATED ALWAYS AS ... VIRTUAL */ #define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */ +#define COLFLAG_BUSY 0x0080 /* Blocks recursion on VIRTUAL columns */ #define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */ #define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */ From ab3c5f26ab72222c4ab0fdcee559b3e3a7c0d53b Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 17 Oct 2019 13:15:40 +0000 Subject: [PATCH 05/31] Fix the table_info and table_xinfo pragmas so that they work with virtual columns. Table_info omits virtual columns. Table_xinfo gives them a "hidden" flag of 2, and 3 for STORED columns. FossilOrigin-Name: 069351b85f9a706f60d3e98fbc8aaf40c374356b967c0464aede30ead3d9d18b --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/pragma.c | 17 ++++++++++++----- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 45942a0a1a..76163c6d4d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C INSERT\swith\snamed\scolumns\sfor\sa\stable\swith\sgenerated\scolumns. -D 2019-10-16T22:01:56.225 +C Fix\sthe\stable_info\sand\stable_xinfo\spragmas\sso\sthat\sthey\swork\swith\svirtual\ncolumns.\s\sTable_info\somits\svirtual\scolumns.\s\sTable_xinfo\sgives\sthem\sa\n"hidden"\sflag\sof\s2,\sand\s3\sfor\sSTORED\scolumns. +D 2019-10-17T13:15:40.320 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -518,7 +518,7 @@ F src/parse.y bc453ce808316facd191413bfa4ec6730a1d693b98fd8be5addef8fbfd62bb7b F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 62714cbd1b7299a6e6a27a587b66b4fd3a836a84e1181e7f96f5c34a50917848 -F src/pragma.c a9511633bc0ee6c67b9ed244d7b1c0770c71e5211d94c8c97d631974166d59b4 +F src/pragma.c 7b4c4040124572d3e477f30a5daf640f7a8ea2f019f7c0a4031633f36ae9935a F src/pragma.h 40962d65b645bb3f08c1f4c456effd01c6e7f073f68ea25177e0c95e181cff75 F src/prepare.c 6049beb71385f017af6fc320d2c75a4e50b75e280c54232442b785fbb83df057 F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 120c6b78cb51532f783014605f1107d40b2e4f54e3852fb1f8f167d0c0b78c69 -R 69bb3625e06cb31ab7b6bfff123323c6 +P 64db39f92d68d1b9f23e48af35e16b969c38b58041fbe900066eeb3ddb291cef +R f385e86a0426e23d58beffa7242fb5ce U drh -Z 504e145f33a96cfe775ae86c4e357f58 +Z 1c8932097c2a1d388102affd6e7e0105 diff --git a/manifest.uuid b/manifest.uuid index 927a0182f2..31afc5e354 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -64db39f92d68d1b9f23e48af35e16b969c38b58041fbe900066eeb3ddb291cef \ No newline at end of file +069351b85f9a706f60d3e98fbc8aaf40c374356b967c0464aede30ead3d9d18b \ No newline at end of file diff --git a/src/pragma.c b/src/pragma.c index 652810eae2..551cc7aa0f 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1100,10 +1100,17 @@ void sqlite3Pragma( sqlite3CodeVerifySchema(pParse, iTabDb); sqlite3ViewGetColumnNames(pParse, pTab); for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ - int isHidden = IsHiddenColumn(pCol); - if( isHidden && pPragma->iArg==0 ){ + int isHidden = 0; + if( pCol->colFlags & COLFLAG_NOINSERT ){ nHidden++; - continue; + if( pPragma->iArg==0 ) continue; + if( pCol->colFlags & COLFLAG_VIRTUAL ){ + isHidden = 2; /* GENERATED ALWAYS AS ... VIRTUAL */ + }else if( pCol->colFlags & COLFLAG_VIRTUAL ){ + isHidden = 3; /* GENERATED ALWAYS AS ... STORED */ + }else{ + isHidden = 1; /* HIDDEN */ + } } if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){ k = 0; @@ -1112,13 +1119,13 @@ void sqlite3Pragma( }else{ for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){} } - assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN ); + assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN || isHidden>=2 ); sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi", i-nHidden, pCol->zName, sqlite3ColumnType(pCol,""), pCol->notNull ? 1 : 0, - pCol->pDflt ? pCol->pDflt->u.zToken : 0, + pCol->pDflt && isHidden<2 ? pCol->pDflt->u.zToken : 0, k, isHidden); } From 676fa25a0f7737d7e233a840a5c2d7dffdccb75a Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 17 Oct 2019 14:21:07 +0000 Subject: [PATCH 06/31] Bug fixes so that "make test" once against runs with no errors. FossilOrigin-Name: 7bfe0f679d8951b3e925bdf549efa0f8d6b514eddeaca69cbfddbd9476cfff5f --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/insert.c | 13 ++++++++----- src/pragma.c | 6 ++++-- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index 76163c6d4d..93dc0ecab7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\stable_info\sand\stable_xinfo\spragmas\sso\sthat\sthey\swork\swith\svirtual\ncolumns.\s\sTable_info\somits\svirtual\scolumns.\s\sTable_xinfo\sgives\sthem\sa\n"hidden"\sflag\sof\s2,\sand\s3\sfor\sSTORED\scolumns. -D 2019-10-17T13:15:40.320 +C Bug\sfixes\sso\sthat\s"make\stest"\sonce\sagainst\sruns\swith\sno\serrors. +D 2019-10-17T14:21:07.409 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 9dabd02b24946f4c38ae7ef566d65abc16476f9d26b3a630261f91e09c726722 +F src/insert.c 3cf6462f09ef50916e5e859b56cb7bbf3a7e0b8f25a9cac0c99c572ba08c0779 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -518,7 +518,7 @@ F src/parse.y bc453ce808316facd191413bfa4ec6730a1d693b98fd8be5addef8fbfd62bb7b F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 62714cbd1b7299a6e6a27a587b66b4fd3a836a84e1181e7f96f5c34a50917848 -F src/pragma.c 7b4c4040124572d3e477f30a5daf640f7a8ea2f019f7c0a4031633f36ae9935a +F src/pragma.c 61abcb6d9f80d06ed3b0d0843a7cef32e96a569a27b94ebfd764dc6c1ce1cd1d F src/pragma.h 40962d65b645bb3f08c1f4c456effd01c6e7f073f68ea25177e0c95e181cff75 F src/prepare.c 6049beb71385f017af6fc320d2c75a4e50b75e280c54232442b785fbb83df057 F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 64db39f92d68d1b9f23e48af35e16b969c38b58041fbe900066eeb3ddb291cef -R f385e86a0426e23d58beffa7242fb5ce +P 069351b85f9a706f60d3e98fbc8aaf40c374356b967c0464aede30ead3d9d18b +R a9daba7f86da0ab938b557a0a9cc8b96 U drh -Z 1c8932097c2a1d388102affd6e7e0105 +Z 1fb219ce2b5d60344f9b3644d927ae0d diff --git a/manifest.uuid b/manifest.uuid index 31afc5e354..0a25f0c923 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -069351b85f9a706f60d3e98fbc8aaf40c374356b967c0464aede30ead3d9d18b \ No newline at end of file +7bfe0f679d8951b3e925bdf549efa0f8d6b514eddeaca69cbfddbd9476cfff5f \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 20b5d9a91c..1c628c670a 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1009,6 +1009,7 @@ void sqlite3Insert( iRegStore = regRowid+1; for(i=0; inCol; i++, iRegStore++){ int k; + u32 colFlags; assert( i>=nHidden ); assert( iRegStore==sqlite3ColumnOfTable(pTab,i)+regRowid+1 ); if( i==pTab->iPKey ){ @@ -1020,16 +1021,18 @@ void sqlite3Insert( sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); continue; } - if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ){ + if( ((colFlags = pTab->aCol[i].colFlags) & COLFLAG_NOINSERT)!=0 ){ nHidden++; - if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ + if( (colFlags & COLFLAG_VIRTUAL)!=0 ){ /* Virtual columns are no stored */ iRegStore--; - }else{ - /* Hidden and stored columns get the default value */ + continue; + }else if( (colFlags & COLFLAG_STORED)!=0 || pColumn==0 ){ + /* Stored columns get the default value. Also hidden columns + ** that are not explicitly named in the INSERT */ sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); + continue; } - continue; } if( pColumn ){ for(j=0; jnId && pColumn->a[j].idx!=i; j++){} diff --git a/src/pragma.c b/src/pragma.c index 551cc7aa0f..d9f249d138 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1102,8 +1102,10 @@ void sqlite3Pragma( for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ int isHidden = 0; if( pCol->colFlags & COLFLAG_NOINSERT ){ - nHidden++; - if( pPragma->iArg==0 ) continue; + if( pPragma->iArg==0 ){ + nHidden++; + continue; + } if( pCol->colFlags & COLFLAG_VIRTUAL ){ isHidden = 2; /* GENERATED ALWAYS AS ... VIRTUAL */ }else if( pCol->colFlags & COLFLAG_VIRTUAL ){ From 8a53ce2ff8a1e7e3fe867662568e13680cbb0e5e Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 17 Oct 2019 15:59:03 +0000 Subject: [PATCH 07/31] Basic UPDATE functionality working for VIRTUAL tables. FossilOrigin-Name: c21959d4eb5d742a097a98e1874c0bf132dc962a97a65be1ab22d6ca3cf2b261 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/update.c | 43 ++++++++++++++++++++++++++++++------------- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 93dc0ecab7..ad6cb4a6ff 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bug\sfixes\sso\sthat\s"make\stest"\sonce\sagainst\sruns\swith\sno\serrors. -D 2019-10-17T14:21:07.409 +C Basic\sUPDATE\sfunctionality\sworking\sfor\sVIRTUAL\stables. +D 2019-10-17T15:59:03.864 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -592,7 +592,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c d3615f0cbe4db5949503bf5916f3cd4fa5de855d5b4ef560f3b6dd5629423a1e F src/treeview.c fddeb413159c3eeeaea3f496172f121cf3695606c461dc4e6dcee51417952df5 F src/trigger.c 845ccc08f60716c58aa28fe6470385c18ef8c4e1d88c93dcf449bc13d464eb2e -F src/update.c 1ad2eb4006a06b13f5eadbbdebe0c4dc7e987428dfdeef18429f533d2dae8618 +F src/update.c ef3e261b43cc417e4d7e59ccf4fdae1b86d9bc1879d83820253e4a2105a63278 F src/upsert.c 710c91bb13e3c3fed5b6fe17cb13e09560bdd003ad8b8c51e6b16c80cfc48b10 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507 F src/util.c 10d910e04a4f3842042485e0df01a484f57f912c10b60b3a09ccddd5019bd138 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 069351b85f9a706f60d3e98fbc8aaf40c374356b967c0464aede30ead3d9d18b -R a9daba7f86da0ab938b557a0a9cc8b96 +P 7bfe0f679d8951b3e925bdf549efa0f8d6b514eddeaca69cbfddbd9476cfff5f +R d18b3efac452c2846ba92424700e5afb U drh -Z 1fb219ce2b5d60344f9b3644d927ae0d +Z f4544de40926466a5b3f8950ba10f06a diff --git a/manifest.uuid b/manifest.uuid index 0a25f0c923..388e90dda5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7bfe0f679d8951b3e925bdf549efa0f8d6b514eddeaca69cbfddbd9476cfff5f \ No newline at end of file +c21959d4eb5d742a097a98e1874c0bf132dc962a97a65be1ab22d6ca3cf2b261 \ No newline at end of file diff --git a/src/update.c b/src/update.c index 9826ae2707..d0685d6589 100644 --- a/src/update.c +++ b/src/update.c @@ -147,7 +147,7 @@ void sqlite3Update( Expr *pLimit, /* LIMIT clause. May be null */ Upsert *pUpsert /* ON CONFLICT clause, or null */ ){ - int i, j; /* Loop counters */ + int i, j, k; /* Loop counters */ Table *pTab; /* The table to be updated */ int addrTop = 0; /* VDBE instruction address of the start of the loop */ WhereInfo *pWInfo; /* Information about the WHERE clause */ @@ -308,6 +308,14 @@ void sqlite3Update( }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ chngPk = 1; } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + else if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ + sqlite3ErrorMsg(pParse, + "cannot UPDATE generated column \"%s\"", + pTab->aCol[j].zName); + goto update_cleanup; + } +#endif aXRef[j] = i; break; } @@ -623,15 +631,20 @@ void sqlite3Update( oldmask |= sqlite3TriggerColmask(pParse, pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError ); - for(i=0; inCol; i++){ + for(i=0, k=regOld; inCol; i++, k++){ + u32 colFlags = pTab->aCol[i].colFlags; + if( colFlags & COLFLAG_VIRTUAL ){ + k--; + continue; + } if( oldmask==0xffffffff || (i<32 && (oldmask & MASKBIT32(i))!=0) - || (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 + || (colFlags & COLFLAG_PRIMKEY)!=0 ){ testcase( oldmask!=0xffffffff && i==31 ); - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, regOld+i); + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, k); }else{ - sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i); + sqlite3VdbeAddOp2(v, OP_Null, 0, k); } } if( chngRowid==0 && pPk==0 ){ @@ -655,13 +668,15 @@ void sqlite3Update( newmask = sqlite3TriggerColmask( pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError ); - for(i=0; inCol; i++){ + for(i=0, k=regNew; inCol; i++, k++){ if( i==pTab->iPKey ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); + sqlite3VdbeAddOp2(v, OP_Null, 0, k); + }else if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)!=0 ){ + k--; }else{ j = aXRef[i]; if( j>=0 ){ - sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i); + sqlite3ExprCode(pParse, pChanges->a[j].pExpr, k); }else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask & MASKBIT32(i)) ){ /* This branch loads the value of a column that will not be changed ** into a register. This is done if there are no BEFORE triggers, or @@ -670,9 +685,9 @@ void sqlite3Update( */ testcase( i==31 ); testcase( i==32 ); - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, regNew+i); + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, k); }else{ - sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); + sqlite3VdbeAddOp2(v, OP_Null, 0, k); } } } @@ -708,9 +723,11 @@ void sqlite3Update( ** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26) ** for an example. */ - for(i=0; inCol; i++){ - if( aXRef[i]<0 && i!=pTab->iPKey ){ - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, regNew+i); + for(i=0, k=regNew; inCol; i++, k++){ + if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ + k--; + }else if( aXRef[i]<0 && i!=pTab->iPKey ){ + sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, k); } } } From ae3977a8f30bb859b858c36d03f07319ba210615 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 17 Oct 2019 16:16:34 +0000 Subject: [PATCH 08/31] Fix the xfer optimization for generated columns, so that VACUUM works again. FossilOrigin-Name: 8f67b89b04622c1509dc102a83be7a80057dc791625804fc2c294089c98b97e4 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/insert.c | 12 +++++++++++- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index ad6cb4a6ff..67a4634513 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Basic\sUPDATE\sfunctionality\sworking\sfor\sVIRTUAL\stables. -D 2019-10-17T15:59:03.864 +C Fix\sthe\sxfer\soptimization\sfor\sgenerated\scolumns,\sso\sthat\sVACUUM\sworks\sagain. +D 2019-10-17T16:16:34.306 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 3cf6462f09ef50916e5e859b56cb7bbf3a7e0b8f25a9cac0c99c572ba08c0779 +F src/insert.c 608b6d99b95f95a657b0fd13048ca002dfa8f1c212771c56bca510f1776f583d F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7bfe0f679d8951b3e925bdf549efa0f8d6b514eddeaca69cbfddbd9476cfff5f -R d18b3efac452c2846ba92424700e5afb +P c21959d4eb5d742a097a98e1874c0bf132dc962a97a65be1ab22d6ca3cf2b261 +R 6aa9977527f4824498ace24e1ab11d24 U drh -Z f4544de40926466a5b3f8950ba10f06a +Z 5abd38c0a3e4636bc9783adf5f0cb09c diff --git a/manifest.uuid b/manifest.uuid index 388e90dda5..adeb66ff57 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c21959d4eb5d742a097a98e1874c0bf132dc962a97a65be1ab22d6ca3cf2b261 \ No newline at end of file +8f67b89b04622c1509dc102a83be7a80057dc791625804fc2c294089c98b97e4 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 1c628c670a..0abe244b34 100644 --- a/src/insert.c +++ b/src/insert.c @@ -2289,6 +2289,10 @@ static int xferOptimization( return 0; /* Neither table may have __hidden__ columns */ } #endif + if( (pDestCol->colFlags & COLFLAG_GENERATED) != + (pSrcCol->colFlags & COLFLAG_GENERATED) ){ + return 0; /* Both columns have the same generated type */ + } if( pDestCol->affinity!=pSrcCol->affinity ){ return 0; /* Affinity must be the same on all columns */ } @@ -2299,7 +2303,7 @@ static int xferOptimization( return 0; /* tab2 must be NOT NULL if tab1 is */ } /* Default values for second and subsequent columns need to match. */ - if( i>0 ){ + if( (pDestCol->colFlags & COLFLAG_GENERATED)==0 && i>0 ){ assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN ); assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN ); if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0) @@ -2309,6 +2313,12 @@ static int xferOptimization( return 0; /* Default values must be the same for all columns */ } } + /* Generator expressions for generated columns must match */ + if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){ + if( sqlite3ExprCompare(0, pSrcCol->pDflt, pDestCol->pDflt, -1)!=0 ){ + return 0; /* Different generator expressions */ + } + } } for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ if( IsUniqueIndex(pDestIdx) ){ From c143114460ec0c214218978baa98b6585649cc22 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 17 Oct 2019 17:54:05 +0000 Subject: [PATCH 09/31] Some (but not all) INSERT and UPDATE statements now work for STORED columns. FossilOrigin-Name: fe7517bf4d360597576ab9aba29627d7926d23f2bbbfb3e7bf4d32761617574c --- manifest | 22 +++++++++++----------- manifest.uuid | 2 +- src/build.c | 7 +++++-- src/insert.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- src/pragma.c | 4 ++-- src/sqliteInt.h | 22 ++++++++++++++++------ src/update.c | 18 ++++++++++++++---- src/vtab.c | 2 +- 8 files changed, 93 insertions(+), 30 deletions(-) diff --git a/manifest b/manifest index 67a4634513..48bf19ebc6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\sxfer\soptimization\sfor\sgenerated\scolumns,\sso\sthat\sVACUUM\sworks\sagain. -D 2019-10-17T16:16:34.306 +C Some\s(but\snot\sall)\sINSERT\sand\sUPDATE\sstatements\snow\swork\sfor\sSTORED\scolumns. +D 2019-10-17T17:54:05.733 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c 6cb40a36b3ec6a4b2dc36e0bd53e42ad448700c48b419569eae711cde4b175d3 +F src/build.c efbcb2e78a578bca138ea2d8a4b3ec44a6fef2630a1b79fb5ed619abd08068e5 F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 608b6d99b95f95a657b0fd13048ca002dfa8f1c212771c56bca510f1776f583d +F src/insert.c 2402847e031cb9b1e95a776481706a38833339be1142e8bdc78fd59e65d7c87c F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -518,7 +518,7 @@ F src/parse.y bc453ce808316facd191413bfa4ec6730a1d693b98fd8be5addef8fbfd62bb7b F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 62714cbd1b7299a6e6a27a587b66b4fd3a836a84e1181e7f96f5c34a50917848 -F src/pragma.c 61abcb6d9f80d06ed3b0d0843a7cef32e96a569a27b94ebfd764dc6c1ce1cd1d +F src/pragma.c c04340e810dd5d6d094f7fffa9278e9183ffd052f91b2dc20f83aea471f8756a F src/pragma.h 40962d65b645bb3f08c1f4c456effd01c6e7f073f68ea25177e0c95e181cff75 F src/prepare.c 6049beb71385f017af6fc320d2c75a4e50b75e280c54232442b785fbb83df057 F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4 @@ -530,7 +530,7 @@ F src/shell.c.in d70bcf630c4073eaa994fa74be98886c781918e794cb8b562be8df10f018e27 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h ecade7aec917068cbbc96505eed645419e07799d91052926d418dd256d60b72d +F src/sqliteInt.h 8af46452e819f6304cc39922eb9f2153a53da44dcedae78cd59ae08e7ca7b164 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -592,7 +592,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c d3615f0cbe4db5949503bf5916f3cd4fa5de855d5b4ef560f3b6dd5629423a1e F src/treeview.c fddeb413159c3eeeaea3f496172f121cf3695606c461dc4e6dcee51417952df5 F src/trigger.c 845ccc08f60716c58aa28fe6470385c18ef8c4e1d88c93dcf449bc13d464eb2e -F src/update.c ef3e261b43cc417e4d7e59ccf4fdae1b86d9bc1879d83820253e4a2105a63278 +F src/update.c a66b56e5024541d2dd6794d0800b14f7a2cc968f6a1fdf84df2cb44048b35058 F src/upsert.c 710c91bb13e3c3fed5b6fe17cb13e09560bdd003ad8b8c51e6b16c80cfc48b10 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507 F src/util.c 10d910e04a4f3842042485e0df01a484f57f912c10b60b3a09ccddd5019bd138 @@ -606,7 +606,7 @@ F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b F src/vdbemem.c d8e10d1773806105e62094c4ede0a4684f46caaf07667a45e6d461e94306b530 F src/vdbesort.c a3be032cc3fee0e3af31773af4a7a6f931b7230a34f53282ccf1d9a2a72343be F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0 -F src/vtab.c 27998d5d738069f2cee981620a1f224558494ce06799d14dcb5e6f34b4cdcdd1 +F src/vtab.c 108f79166d4a232a8bfb9d46e2fbec191f83a87fe97f7b93fc4de976c3fa3434 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c bbd6838bd79c0a32144d482fb0b6a9d2d1a252fb3b16d5005ec30f2f80413b0d F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c21959d4eb5d742a097a98e1874c0bf132dc962a97a65be1ab22d6ca3cf2b261 -R 6aa9977527f4824498ace24e1ab11d24 +P 8f67b89b04622c1509dc102a83be7a80057dc791625804fc2c294089c98b97e4 +R f8d479928377499694b42044f6469958 U drh -Z 5abd38c0a3e4636bc9783adf5f0cb09c +Z aaf8a72afb67fb32144fc0364d09d870 diff --git a/manifest.uuid b/manifest.uuid index adeb66ff57..b3a551e5d8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8f67b89b04622c1509dc102a83be7a80057dc791625804fc2c294089c98b97e4 \ No newline at end of file +fe7517bf4d360597576ab9aba29627d7926d23f2bbbfb3e7bf4d32761617574c \ No newline at end of file diff --git a/src/build.c b/src/build.c index 897e9183eb..6937d6af28 100644 --- a/src/build.c +++ b/src/build.c @@ -1564,8 +1564,11 @@ void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ goto generated_error; } } - pTab->nVCol++; + if( eType==COLFLAG_VIRTUAL ) pTab->nVCol++; pCol->colFlags |= eType; + assert( TF_HasVirtual==COLFLAG_VIRTUAL ); + assert( TF_HasStored==COLFLAG_STORED ); + pTab->tabFlags |= eType; pCol->pDflt = sqlite3ExprDup(pParse->db, pExpr, 0); goto generated_done; @@ -2177,7 +2180,7 @@ void sqlite3EndTable( } #endif /* !defined(SQLITE_OMIT_CHECK) */ #ifndef SQLITE_OMIT_GENERATED_COLUMNS - if( p->nVCol ){ + if( p->tabFlags & (TF_HasVirtual|TF_HasStored) ){ int ii; for(ii=0; iinCol; ii++){ if( (p->aCol[ii].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL))!=0 ){ diff --git a/src/insert.c b/src/insert.c index 0abe244b34..04b91d8405 100644 --- a/src/insert.c +++ b/src/insert.c @@ -202,6 +202,36 @@ static int readsTable(Parse *p, int iDb, Table *pTab){ return 0; } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS +/* +** All regular columns for table pTab have been puts into registers +** starting with iRegStore. The registers that correspond to STORED +** columns have not been initialized. This routine goes back and computes +** the values for STORED columns based on the previously computed normal +** columns. +*/ +void sqlite3ComputeStoredColumns( + Parse *pParse, /* Parsing context */ + int iRegStore, /* Register holding the first column */ + Table *pTab /* The table */ +){ + int i; + pParse->iSelfTab = -iRegStore; + for(i=0; inCol; i++, iRegStore++){ + u32 colFlags = pTab->aCol[i].colFlags; + if( (colFlags & COLFLAG_VIRTUAL)!=0 ){ + /* Virtual columns are no stored */ + iRegStore--; + }else if( (colFlags & COLFLAG_STORED)!=0 ){ + /* Stored columns are handled on the second pass */ + sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore); + } + } + pParse->iSelfTab = 0; +} +#endif /* SQLITE_OMIT_GENERATED_COLUMNS */ + + #ifndef SQLITE_OMIT_AUTOINCREMENT /* ** Locate or create an AutoincInfo structure associated with table pTab @@ -1027,9 +1057,11 @@ void sqlite3Insert( /* Virtual columns are no stored */ iRegStore--; continue; - }else if( (colFlags & COLFLAG_STORED)!=0 || pColumn==0 ){ - /* Stored columns get the default value. Also hidden columns - ** that are not explicitly named in the INSERT */ + }else if( (colFlags & COLFLAG_STORED)!=0 ){ + /* Stored columns are handled on the second pass */ + continue; + }else if( pColumn==0 ){ + /* Hidden columns that are not explicitly named in the INSERT */ sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); continue; } @@ -1061,6 +1093,14 @@ void sqlite3Insert( } } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + /* Compute the new value for STORED columns after all other + ** columns have already been computed */ + if( pTab->tabFlags & TF_HasStored ){ + sqlite3ComputeStoredColumns(pParse, regRowid+1, pTab); + } +#endif + /* Generate code to check constraints and generate index keys and ** do the insertion. */ diff --git a/src/pragma.c b/src/pragma.c index d9f249d138..a3dfff2b73 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1108,9 +1108,9 @@ void sqlite3Pragma( } if( pCol->colFlags & COLFLAG_VIRTUAL ){ isHidden = 2; /* GENERATED ALWAYS AS ... VIRTUAL */ - }else if( pCol->colFlags & COLFLAG_VIRTUAL ){ + }else if( pCol->colFlags & COLFLAG_STORED ){ isHidden = 3; /* GENERATED ALWAYS AS ... STORED */ - }else{ + }else{ assert( pCol->colFlags & COLFLAG_HIDDEN ); isHidden = 1; /* HIDDEN */ } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 8455155ae0..508487954c 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2009,20 +2009,27 @@ struct Table { ** followed by non-hidden columns. Example: "CREATE VIRTUAL TABLE x USING ** vtab1(a HIDDEN, b);". Since "b" is a non-hidden column but "a" is hidden, ** the TF_OOOHidden attribute would apply in this case. Such tables require -** special handling during INSERT processing. +** special handling during INSERT processing. The "OOO" means "Out Of Order". +** +** Constraints: +** +** TF_HasVirtual == COLFLAG_Virtual +** TF_HasStored == COLFLAG_Stored */ #define TF_Readonly 0x0001 /* Read-only system table */ #define TF_Ephemeral 0x0002 /* An ephemeral table */ #define TF_HasPrimaryKey 0x0004 /* Table has a primary key */ #define TF_Autoincrement 0x0008 /* Integer primary key is autoincrement */ #define TF_HasStat1 0x0010 /* nRowLogEst set from sqlite_stat1 */ -#define TF_WithoutRowid 0x0020 /* No rowid. PRIMARY KEY is the key */ -#define TF_NoVisibleRowid 0x0040 /* No user-visible "rowid" column */ -#define TF_OOOHidden 0x0080 /* Out-of-Order hidden columns */ +#define TF_HasVirtual 0x0020 /* Has one or more VIRTUAL columns */ +#define TF_HasStored 0x0040 /* Has one or more STORED columns */ +#define TF_WithoutRowid 0x0080 /* No rowid. PRIMARY KEY is the key */ #define TF_StatsUsed 0x0100 /* Query planner decisions affected by ** Index.aiRowLogEst[] values */ -#define TF_HasNotNull 0x0200 /* Contains NOT NULL constraints */ -#define TF_Shadow 0x0400 /* True for a shadow table */ +#define TF_NoVisibleRowid 0x0200 /* No user-visible "rowid" column */ +#define TF_OOOHidden 0x0400 /* Out-of-Order hidden columns */ +#define TF_HasNotNull 0x0800 /* Contains NOT NULL constraints */ +#define TF_Shadow 0x1000 /* True for a shadow table */ /* ** Test to see whether or not a table is a virtual table. This is @@ -4020,6 +4027,9 @@ void sqlite3FreeIndex(sqlite3*, Index*); # define sqlite3AutoincrementEnd(X) #endif void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*); +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + void sqlite3ComputeStoredColumns(Parse*, int, Table*); +#endif void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*); IdList *sqlite3IdListAppend(Parse*, IdList*, Token*); int sqlite3IdListIndex(IdList*,const char*); diff --git a/src/update.c b/src/update.c index d0685d6589..9b29757921 100644 --- a/src/update.c +++ b/src/update.c @@ -671,8 +671,8 @@ void sqlite3Update( for(i=0, k=regNew; inCol; i++, k++){ if( i==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Null, 0, k); - }else if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)!=0 ){ - k--; + }else if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)!=0 ){ + if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--; }else{ j = aXRef[i]; if( j>=0 ){ @@ -691,6 +691,11 @@ void sqlite3Update( } } } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( pTab->tabFlags & TF_HasStored ){ + sqlite3ComputeStoredColumns(pParse, regNew, pTab); + } +#endif /* Fire any BEFORE UPDATE triggers. This happens before constraints are ** verified. One could argue that this is wrong. @@ -724,12 +729,17 @@ void sqlite3Update( ** for an example. */ for(i=0, k=regNew; inCol; i++, k++){ - if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ - k--; + if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ + if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--; }else if( aXRef[i]<0 && i!=pTab->iPKey ){ sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, k); } } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( pTab->tabFlags & TF_HasStored ){ + sqlite3ComputeStoredColumns(pParse, regNew, pTab); + } +#endif } if( !isView ){ diff --git a/src/vtab.c b/src/vtab.c index 33a38021f5..a2032c7ae0 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -624,7 +624,7 @@ static int vtabCallConstructor( rc = SQLITE_ERROR; }else{ int iCol; - u8 oooHidden = 0; + u16 oooHidden = 0; /* If everything went according to plan, link the new VTable structure ** into the linked list headed by pTab->pVTable. Then loop through the ** columns of the table to see if any of them contain the token "hidden". From d4cd292c2aa7e453ee3879d47df0c0503b47db75 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 17 Oct 2019 18:07:22 +0000 Subject: [PATCH 10/31] Bug fix with INSERT using an explicit column list on a table with a non-final STORED column. FossilOrigin-Name: 61b4459ae6a6cc182c11abbc8b1dd629f77beb088d7ccad5e563d8d4769056df --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/insert.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 48bf19ebc6..9ad58ca2f9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Some\s(but\snot\sall)\sINSERT\sand\sUPDATE\sstatements\snow\swork\sfor\sSTORED\scolumns. -D 2019-10-17T17:54:05.733 +C Bug\sfix\swith\sINSERT\susing\san\sexplicit\scolumn\slist\son\sa\stable\swith\na\snon-final\sSTORED\scolumn. +D 2019-10-17T18:07:22.142 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 2402847e031cb9b1e95a776481706a38833339be1142e8bdc78fd59e65d7c87c +F src/insert.c 603a076777fc517847c55bcb5e6ab96191c1727ef4bf353f7154f2770cd352c2 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 8f67b89b04622c1509dc102a83be7a80057dc791625804fc2c294089c98b97e4 -R f8d479928377499694b42044f6469958 +P fe7517bf4d360597576ab9aba29627d7926d23f2bbbfb3e7bf4d32761617574c +R 1758d4287c38e70ebe46598e4b662121 U drh -Z aaf8a72afb67fb32144fc0364d09d870 +Z d0910071efb9b72075e77f5cb05b8223 diff --git a/manifest.uuid b/manifest.uuid index b3a551e5d8..9cc2345c09 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fe7517bf4d360597576ab9aba29627d7926d23f2bbbfb3e7bf4d32761617574c \ No newline at end of file +61b4459ae6a6cc182c11abbc8b1dd629f77beb088d7ccad5e563d8d4769056df \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 04b91d8405..0a140fd4cd 100644 --- a/src/insert.c +++ b/src/insert.c @@ -220,7 +220,7 @@ void sqlite3ComputeStoredColumns( for(i=0; inCol; i++, iRegStore++){ u32 colFlags = pTab->aCol[i].colFlags; if( (colFlags & COLFLAG_VIRTUAL)!=0 ){ - /* Virtual columns are no stored */ + /* Virtual columns are not stored */ iRegStore--; }else if( (colFlags & COLFLAG_STORED)!=0 ){ /* Stored columns are handled on the second pass */ @@ -694,7 +694,7 @@ void sqlite3Insert( ** is appears in the original table. (The index of the INTEGER ** PRIMARY KEY in the original table is pTab->iPKey.) */ - bIdListInOrder = (pTab->tabFlags & TF_OOOHidden)==0; + bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0; if( pColumn ){ for(i=0; inId; i++){ pColumn->a[i].idx = -1; From 0b0b3a95d025430c83563ee390656901734f9988 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 17 Oct 2019 18:35:57 +0000 Subject: [PATCH 11/31] In the Table object, change the nVCol field to nNVCol - the number of non-virtual columns, as that is the quantity that we need most. FossilOrigin-Name: 4ad66af04a654d92711d2d056ce8f35cd21eac4b99fb8d78be1a314620b6d29e --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/build.c | 11 ++++++++--- src/insert.c | 6 ++---- src/pragma.c | 2 +- src/sqliteInt.h | 2 +- 6 files changed, 22 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index 9ad58ca2f9..69da213089 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bug\sfix\swith\sINSERT\susing\san\sexplicit\scolumn\slist\son\sa\stable\swith\na\snon-final\sSTORED\scolumn. -D 2019-10-17T18:07:22.142 +C In\sthe\sTable\sobject,\schange\sthe\snVCol\sfield\sto\snNVCol\s-\sthe\snumber\sof\nnon-virtual\scolumns,\sas\sthat\sis\sthe\squantity\sthat\swe\sneed\smost. +D 2019-10-17T18:35:57.978 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c efbcb2e78a578bca138ea2d8a4b3ec44a6fef2630a1b79fb5ed619abd08068e5 +F src/build.c a6424bece3662d57b19f8ead1541c959036bc632ac57f7f6f7801833c8e544da F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 603a076777fc517847c55bcb5e6ab96191c1727ef4bf353f7154f2770cd352c2 +F src/insert.c 96e3cd32ddc5cfc75b2a03ced36f49a31105cfbda3939f1e239109bdd12227e8 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -518,7 +518,7 @@ F src/parse.y bc453ce808316facd191413bfa4ec6730a1d693b98fd8be5addef8fbfd62bb7b F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 62714cbd1b7299a6e6a27a587b66b4fd3a836a84e1181e7f96f5c34a50917848 -F src/pragma.c c04340e810dd5d6d094f7fffa9278e9183ffd052f91b2dc20f83aea471f8756a +F src/pragma.c a2cee4630b456f1f4727f93e2813d1cd197965c2ba2105be30f4c6104343727f F src/pragma.h 40962d65b645bb3f08c1f4c456effd01c6e7f073f68ea25177e0c95e181cff75 F src/prepare.c 6049beb71385f017af6fc320d2c75a4e50b75e280c54232442b785fbb83df057 F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4 @@ -530,7 +530,7 @@ F src/shell.c.in d70bcf630c4073eaa994fa74be98886c781918e794cb8b562be8df10f018e27 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h 8af46452e819f6304cc39922eb9f2153a53da44dcedae78cd59ae08e7ca7b164 +F src/sqliteInt.h 67d8d7f2d734823a978e50764563046759c23c6fa752c91e4f33b9815539e3e1 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P fe7517bf4d360597576ab9aba29627d7926d23f2bbbfb3e7bf4d32761617574c -R 1758d4287c38e70ebe46598e4b662121 +P 61b4459ae6a6cc182c11abbc8b1dd629f77beb088d7ccad5e563d8d4769056df +R 3d476f0303fa6cd5641db0923ba30a4b U drh -Z d0910071efb9b72075e77f5cb05b8223 +Z 39ac0138a046fe5fcbf36ab2cfc09aa2 diff --git a/manifest.uuid b/manifest.uuid index 9cc2345c09..480b2fbc94 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -61b4459ae6a6cc182c11abbc8b1dd629f77beb088d7ccad5e563d8d4769056df \ No newline at end of file +4ad66af04a654d92711d2d056ce8f35cd21eac4b99fb8d78be1a314620b6d29e \ No newline at end of file diff --git a/src/build.c b/src/build.c index 6937d6af28..ebb5243997 100644 --- a/src/build.c +++ b/src/build.c @@ -901,7 +901,7 @@ i16 sqlite3ColumnOfTable(Table *pTab, i16 iCol){ int i; i16 n; assert( iColnCol ); - if( pTab->nVCol==0 ) return iCol; + if( (pTab->tabFlags & TF_HasVirtual)==0 ) return iCol; for(i=0, n=0; iaCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) n++; } @@ -1564,7 +1564,6 @@ void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ goto generated_error; } } - if( eType==COLFLAG_VIRTUAL ) pTab->nVCol++; pCol->colFlags |= eType; assert( TF_HasVirtual==COLFLAG_VIRTUAL ); assert( TF_HasStored==COLFLAG_STORED ); @@ -2127,6 +2126,7 @@ void sqlite3EndTable( assert( !db->mallocFailed ); p = pParse->pNewTable; if( p==0 ) return; + p->nNVCol = p->nCol; if( pSelect==0 && isShadowTableName(db, p->zName) ){ p->tabFlags |= TF_Shadow; @@ -2183,7 +2183,12 @@ void sqlite3EndTable( if( p->tabFlags & (TF_HasVirtual|TF_HasStored) ){ int ii; for(ii=0; iinCol; ii++){ - if( (p->aCol[ii].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL))!=0 ){ + u32 colFlags = p->aCol[ii].colFlags; + if( (colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL))!=0 ){ + if( colFlags & COLFLAG_VIRTUAL ){ + p->nNVCol--; + assert( p->nNVCol>=0 ); + } sqlite3ResolveSelfReference(pParse, p, NC_GenCol, p->aCol[ii].pDflt, 0); } diff --git a/src/insert.c b/src/insert.c index 0a140fd4cd..cd3eaf293d 100644 --- a/src/insert.c +++ b/src/insert.c @@ -37,8 +37,7 @@ void sqlite3OpenTable( sqlite3TableLock(pParse, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName); if( HasRowid(pTab) ){ - sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, - pTab->nCol - pTab->nVCol); + sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol); VdbeComment((v, "%s", pTab->zName)); }else{ Index *pPk = sqlite3PrimaryKeyIndex(pTab); @@ -1933,8 +1932,7 @@ void sqlite3GenerateConstraintChecks( /* Generate the table record */ if( HasRowid(pTab) ){ int regRec = aRegIdx[ix]; - sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData+1, - pTab->nCol-pTab->nVCol, regRec); + sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData+1, pTab->nNVCol, regRec); sqlite3SetMakeRecordP5(v, pTab); if( !bAffinityDone ){ sqlite3TableAffinity(v, pTab, 0); diff --git a/src/pragma.c b/src/pragma.c index a3dfff2b73..750ddb1404 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1586,7 +1586,7 @@ void sqlite3Pragma( loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); if( !isQuick ){ /* Sanity check on record header decoding */ - sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-pTab->nVCol-1,3); + sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); } /* Verify that all NOT NULL columns really are NOT NULL */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 508487954c..2726a0ac4e 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1982,7 +1982,7 @@ struct Table { u32 tabFlags; /* Mask of TF_* values */ i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */ i16 nCol; /* Number of columns in this table */ - i16 nVCol; /* Number of virtual columns */ + i16 nNVCol; /* Number of columns that are not VIRTUAL */ LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ #ifdef SQLITE_ENABLE_COSTMULT From 9942ef0d95c5a34bec24b669f454fc157bbf8eee Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 18 Oct 2019 02:19:18 +0000 Subject: [PATCH 12/31] STORED columns can now reference other STORED columns, in any order, as long as there are not loops. FossilOrigin-Name: 0d236698e64b2a4b46f91a25279c406e0bf392fe66116678456f0a034c11d7b4 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/expr.c | 46 ++++++++++++++++++++++++++++++++++++++-------- src/insert.c | 17 ++++++++++++++++- src/sqliteInt.h | 5 +++-- 5 files changed, 66 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 69da213089..9e844296d9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sTable\sobject,\schange\sthe\snVCol\sfield\sto\snNVCol\s-\sthe\snumber\sof\nnon-virtual\scolumns,\sas\sthat\sis\sthe\squantity\sthat\swe\sneed\smost. -D 2019-10-17T18:35:57.978 +C STORED\scolumns\scan\snow\sreference\sother\sSTORED\scolumns,\sin\sany\sorder,\sas\slong\nas\sthere\sare\snot\sloops. +D 2019-10-18T02:19:18.134 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -477,7 +477,7 @@ F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319 F src/delete.c fd10ac325c73bdf4d558530745d70df01fe6f7a0763553045adf42a62c303dc9 -F src/expr.c 61d9043b1b9b82d72c919bcf5801a885a0ee7e41bf3e5ce3021b206a5706a949 +F src/expr.c e492fffa17f9b89ba01790715d8f6b3a14b1af6b486163a6690b3fee4b3e4529 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 6271fda51794b569d736eba4097d28f13080cd0c9eb66d5fcecb4b77336fae50 F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 96e3cd32ddc5cfc75b2a03ced36f49a31105cfbda3939f1e239109bdd12227e8 +F src/insert.c 3115663711fabc6a79b96f4c5f1a4cd64f79778c51a1f18b4180c2959785f636 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -530,7 +530,7 @@ F src/shell.c.in d70bcf630c4073eaa994fa74be98886c781918e794cb8b562be8df10f018e27 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h 67d8d7f2d734823a978e50764563046759c23c6fa752c91e4f33b9815539e3e1 +F src/sqliteInt.h aa16ccbbe83b06807da56079398412a995c904e0c0bb5a18eb5c659eb5c96898 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 61b4459ae6a6cc182c11abbc8b1dd629f77beb088d7ccad5e563d8d4769056df -R 3d476f0303fa6cd5641db0923ba30a4b +P 4ad66af04a654d92711d2d056ce8f35cd21eac4b99fb8d78be1a314620b6d29e +R 9578e8b1b10efcdb33ad67045419d288 U drh -Z 39ac0138a046fe5fcbf36ab2cfc09aa2 +Z f6acd0d3a8cdd8b86a336efd8f5324bf diff --git a/manifest.uuid b/manifest.uuid index 480b2fbc94..c8abb502de 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4ad66af04a654d92711d2d056ce8f35cd21eac4b99fb8d78be1a314620b6d29e \ No newline at end of file +0d236698e64b2a4b46f91a25279c406e0bf392fe66116678456f0a034c11d7b4 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index c21006b115..c026c9583b 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3577,19 +3577,49 @@ expr_code_doover: } if( iTab<0 ){ if( pParse->iSelfTab<0 ){ - /* Generating CHECK constraints or inserting into partial index */ - assert( pExpr->y.pTab!=0 ); + /* Other columns in the same row for CHECK constraints or + ** generated columns or for inserting into partial index. + ** The row is unpacked into registers beginning at + ** 0-(pParse->iSelfTab). The rowid (if any) is in a register + ** immediately prior to the first column. + */ + Column *pCol; + Table *pTab = pExpr->y.pTab; + int iSrc; + assert( pTab!=0 ); assert( pExpr->iColumn>=XN_ROWID ); assert( pExpr->iColumny.pTab->nCol ); - if( pExpr->iColumn>=0 - && pExpr->y.pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL - ){ - sqlite3VdbeAddOp2(v, OP_SCopy, pExpr->iColumn - pParse->iSelfTab, - target); + if( pExpr->iColumn<0 ){ + return -1-pParse->iSelfTab; + } + pCol = pTab->aCol + pExpr->iColumn; + iSrc = sqlite3ColumnOfTable(pTab, pExpr->iColumn) - pParse->iSelfTab; +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( pCol->colFlags & COLFLAG_GENERATED ){ + if( pCol->colFlags & COLFLAG_BUSY ){ + sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", + pCol->zName); + return 0; + } + pCol->colFlags |= COLFLAG_BUSY; + if( pCol->colFlags & COLFLAG_VIRTUAL ){ + target = sqlite3ExprCodeTarget(pParse, pCol->pDflt, target); + }else{ + target = iSrc; + if( pCol->colFlags & COLFLAG_NOTAVAIL ){ + sqlite3ExprCode(pParse, pCol->pDflt, iSrc); + } + } + pCol->colFlags &= ~(COLFLAG_BUSY|COLFLAG_NOTAVAIL); + return target; + }else +#endif /* SQLITE_OMIT_GENERATED_COLUMNS */ + if( pCol->affinity==SQLITE_AFF_REAL ){ + sqlite3VdbeAddOp2(v, OP_SCopy, iSrc, target); sqlite3VdbeAddOp1(v, OP_RealAffinity, target); return target; }else{ - return pExpr->iColumn - pParse->iSelfTab; + return iSrc; } }else{ /* Coding an expression that is part of an index where column names diff --git a/src/insert.c b/src/insert.c index cd3eaf293d..d53db3dd3e 100644 --- a/src/insert.c +++ b/src/insert.c @@ -215,15 +215,30 @@ void sqlite3ComputeStoredColumns( Table *pTab /* The table */ ){ int i; + /* Because there can be multiple STORED columns that refer to one another, + ** either directly or through VIRTUAL columns, this is a two pass + ** algorithm. On the first pass, mark all STORED columns as NOT-AVAILABLE. + */ + for(i=0; inCol; i++){ + if( pTab->aCol[i].colFlags & COLFLAG_STORED ){ + pTab->aCol[i].colFlags |= COLFLAG_NOTAVAIL; + } + } + /* On the second pass, compute the value of each NOT-AVAILABLE column. + ** Companion code in the TK_COLUMN case of sqlite3ExprCodeTarget() will + ** compute dependencies and mark remove the COLSPAN_NOTAVAIL mark, as + ** they are needed. + */ pParse->iSelfTab = -iRegStore; for(i=0; inCol; i++, iRegStore++){ u32 colFlags = pTab->aCol[i].colFlags; if( (colFlags & COLFLAG_VIRTUAL)!=0 ){ /* Virtual columns are not stored */ iRegStore--; - }else if( (colFlags & COLFLAG_STORED)!=0 ){ + }else if( (colFlags & COLFLAG_NOTAVAIL)!=0 ){ /* Stored columns are handled on the second pass */ sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore); + colFlags &= ~COLFLAG_NOTAVAIL; } } pParse->iSelfTab = 0; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 2726a0ac4e..f6646e4b82 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1828,7 +1828,7 @@ struct Column { u8 notNull; /* An OE_ code for handling a NOT NULL constraint */ char affinity; /* One of the SQLITE_AFF_... values */ u8 szEst; /* Estimated size of value in this column. sizeof(INT)==1 */ - u8 colFlags; /* Boolean properties. See COLFLAG_ defines below */ + u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */ }; /* Allowed values for Column.colFlags: @@ -1840,7 +1840,8 @@ struct Column { #define COLFLAG_SORTERREF 0x0010 /* Use sorter-refs with this column */ #define COLFLAG_VIRTUAL 0x0020 /* GENERATED ALWAYS AS ... VIRTUAL */ #define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */ -#define COLFLAG_BUSY 0x0080 /* Blocks recursion on VIRTUAL columns */ +#define COLFLAG_BUSY 0x0080 /* Blocks recursion on GENERATED columns */ +#define COLFLAG_NOTAVAIL 0x0100 /* STORED column not yet calculated */ #define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */ #define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */ From 463e76ff8f024ca12d1bad4c6ab23e3a7a8247ce Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 18 Oct 2019 10:05:06 +0000 Subject: [PATCH 13/31] Get indexes working on virtual columns. FossilOrigin-Name: 450c48766c8e62653d074c95f69b0576de3880d183a1d1e5992d88b6fce6cc39 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/insert.c | 21 ++++++++++++++------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index 9e844296d9..ec2dc19b00 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C STORED\scolumns\scan\snow\sreference\sother\sSTORED\scolumns,\sin\sany\sorder,\sas\slong\nas\sthere\sare\snot\sloops. -D 2019-10-18T02:19:18.134 +C Get\sindexes\sworking\son\svirtual\scolumns. +D 2019-10-18T10:05:06.425 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 3115663711fabc6a79b96f4c5f1a4cd64f79778c51a1f18b4180c2959785f636 +F src/insert.c 689b21b415d4bfe2a0ea2cf0066974d2a93899fa51af12453664214fa0d534e6 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 4ad66af04a654d92711d2d056ce8f35cd21eac4b99fb8d78be1a314620b6d29e -R 9578e8b1b10efcdb33ad67045419d288 +P 0d236698e64b2a4b46f91a25279c406e0bf392fe66116678456f0a034c11d7b4 +R 8109a098652bad982748ade2c7597bbf U drh -Z f6acd0d3a8cdd8b86a336efd8f5324bf +Z 4e41794c6cc4f099bab016eb4fec67c3 diff --git a/manifest.uuid b/manifest.uuid index c8abb502de..37fa61007b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0d236698e64b2a4b46f91a25279c406e0bf392fe66116678456f0a034c11d7b4 \ No newline at end of file +450c48766c8e62653d074c95f69b0576de3880d183a1d1e5992d88b6fce6cc39 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index d53db3dd3e..f3bfeb4f60 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1755,14 +1755,21 @@ void sqlite3GenerateConstraintChecks( sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i); pParse->iSelfTab = 0; VdbeComment((v, "%s column %d", pIdx->zName, i)); + }else if( iField==XN_ROWID || iField==pTab->iPKey ){ + x = regNewData; + sqlite3VdbeAddOp2(v, OP_IntCopy, x, regIdx+i); + VdbeComment((v, "rowid")); +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + }else if( pTab->aCol[iField].colFlags & COLFLAG_VIRTUAL ){ + pParse->iSelfTab = -(regNewData+1); + sqlite3ExprCodeCopy(pParse, pTab->aCol[iField].pDflt, regIdx+i); + pParse->iSelfTab = 0; + VdbeComment((v, "%s column %d", pIdx->zName, i)); +#endif }else{ - if( iField==XN_ROWID || iField==pTab->iPKey ){ - x = regNewData; - }else{ - x = iField + regNewData + 1; - } - sqlite3VdbeAddOp2(v, iField<0 ? OP_IntCopy : OP_SCopy, x, regIdx+i); - VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName)); + x = sqlite3ColumnOfTable(pTab, iField) + regNewData + 1; + sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); + VdbeComment((v, "%s", pTab->aCol[iField].zName)); } } sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); From 01ef55e0f55e3dd49f4d70177e6e03e540a1eae5 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 18 Oct 2019 12:14:48 +0000 Subject: [PATCH 14/31] Fix sqlite3ColumnOfIndex() to account for virtual columns. FossilOrigin-Name: 447271123e3b467d9271a4c0cf27f47af2f865c9298b8c355d9e766411a1f422 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/build.c | 8 ++++++++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index ec2dc19b00..8b1604787a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Get\sindexes\sworking\son\svirtual\scolumns. -D 2019-10-18T10:05:06.425 +C Fix\ssqlite3ColumnOfIndex()\sto\saccount\sfor\svirtual\scolumns. +D 2019-10-18T12:14:48.871 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c a6424bece3662d57b19f8ead1541c959036bc632ac57f7f6f7801833c8e544da +F src/build.c 5e5fc50bda07b83d8f602218dae3099c9b7ee7b71d6d59dfa642dc074877ec35 F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 0d236698e64b2a4b46f91a25279c406e0bf392fe66116678456f0a034c11d7b4 -R 8109a098652bad982748ade2c7597bbf +P 450c48766c8e62653d074c95f69b0576de3880d183a1d1e5992d88b6fce6cc39 +R b12f2d235ff67ce42b63b55b4cb45601 U drh -Z 4e41794c6cc4f099bab016eb4fec67c3 +Z c0d073b04d67e49c297ac9c42fae3a3a diff --git a/manifest.uuid b/manifest.uuid index 37fa61007b..d4b8a06657 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -450c48766c8e62653d074c95f69b0576de3880d183a1d1e5992d88b6fce6cc39 \ No newline at end of file +447271123e3b467d9271a4c0cf27f47af2f865c9298b8c355d9e766411a1f422 \ No newline at end of file diff --git a/src/build.c b/src/build.c index ebb5243997..3441e07779 100644 --- a/src/build.c +++ b/src/build.c @@ -882,6 +882,14 @@ Index *sqlite3PrimaryKeyIndex(Table *pTab){ */ i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){ int i; +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + Table *pTab = pIdx->pTable; + if( pTab->tabFlags & TF_HasVirtual ){ + for(i=0; i<=iCol; i++){ + if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) iCol++; + } + } +#endif for(i=0; inColumn; i++){ if( iCol==pIdx->aiColumn[i] ) return i; } From 6df9c4b990059e43845f60752ae18565ddb7d702 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 18 Oct 2019 12:52:08 +0000 Subject: [PATCH 15/31] Claw back some performance from the sqlite3ExprGetColumnOfTable() routine. FossilOrigin-Name: e8426acb94179ff49549aced6ea3c26c49ba4761c2f414fa1772d6a031edc79d --- manifest | 28 ++++++++++++++-------------- manifest.uuid | 2 +- src/delete.c | 7 +++---- src/expr.c | 10 ++++------ src/pragma.c | 4 ++-- src/select.c | 2 +- src/sqliteInt.h | 2 +- src/update.c | 8 ++++---- src/vdbe.h | 1 + src/vdbeaux.c | 7 +++++++ src/wherecode.c | 4 ++-- 11 files changed, 40 insertions(+), 35 deletions(-) diff --git a/manifest b/manifest index 8b1604787a..281510f5d9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\ssqlite3ColumnOfIndex()\sto\saccount\sfor\svirtual\scolumns. -D 2019-10-18T12:14:48.871 +C Claw\sback\ssome\sperformance\sfrom\sthe\ssqlite3ExprGetColumnOfTable()\sroutine. +D 2019-10-18T12:52:08.655 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -476,8 +476,8 @@ F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319 -F src/delete.c fd10ac325c73bdf4d558530745d70df01fe6f7a0763553045adf42a62c303dc9 -F src/expr.c e492fffa17f9b89ba01790715d8f6b3a14b1af6b486163a6690b3fee4b3e4529 +F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf +F src/expr.c e2c2f78c9f63de2bedabf34f8f25968c6b2317313d1ef15a37c8aa9bd29dcf75 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 6271fda51794b569d736eba4097d28f13080cd0c9eb66d5fcecb4b77336fae50 F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12 @@ -518,19 +518,19 @@ F src/parse.y bc453ce808316facd191413bfa4ec6730a1d693b98fd8be5addef8fbfd62bb7b F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 62714cbd1b7299a6e6a27a587b66b4fd3a836a84e1181e7f96f5c34a50917848 -F src/pragma.c a2cee4630b456f1f4727f93e2813d1cd197965c2ba2105be30f4c6104343727f +F src/pragma.c 986fdd27f1ddb712eaf7af4ac5c4d7e0ad97ce9c5d2f069e02f89bb7e7d06496 F src/pragma.h 40962d65b645bb3f08c1f4c456effd01c6e7f073f68ea25177e0c95e181cff75 F src/prepare.c 6049beb71385f017af6fc320d2c75a4e50b75e280c54232442b785fbb83df057 F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 2160146697e6e0ba251b5a954e16f542b6e684fb4778cec2994094ab401ef996 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 -F src/select.c ac9270006d5e1c283012fe116f36a8d496a49a296943f777176f61c0c903ea00 +F src/select.c 7ef05eeb7f686f84dd1428cbdca280c898915bbf56e1ea97bd42ecc070af78d3 F src/shell.c.in d70bcf630c4073eaa994fa74be98886c781918e794cb8b562be8df10f018e274 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h aa16ccbbe83b06807da56079398412a995c904e0c0bb5a18eb5c659eb5c96898 +F src/sqliteInt.h 769a3d9f244fe08c219aadc8474d180e3adca2c26cb5b13603adef4910b6ccf1 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -592,16 +592,16 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c d3615f0cbe4db5949503bf5916f3cd4fa5de855d5b4ef560f3b6dd5629423a1e F src/treeview.c fddeb413159c3eeeaea3f496172f121cf3695606c461dc4e6dcee51417952df5 F src/trigger.c 845ccc08f60716c58aa28fe6470385c18ef8c4e1d88c93dcf449bc13d464eb2e -F src/update.c a66b56e5024541d2dd6794d0800b14f7a2cc968f6a1fdf84df2cb44048b35058 +F src/update.c c9020ecd59e80836a1bfccc406af3658a18bada4f17319fcc791db6643cbcac0 F src/upsert.c 710c91bb13e3c3fed5b6fe17cb13e09560bdd003ad8b8c51e6b16c80cfc48b10 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507 F src/util.c 10d910e04a4f3842042485e0df01a484f57f912c10b60b3a09ccddd5019bd138 F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf F src/vdbe.c 9a3f4c2ec6c45e4bd5db465e77e79dfdf5bdc5cf3a8c0bfe9549da209b9c18bc -F src/vdbe.h 3f2b571e702e77e6bf031f0236e554aedfae643e991f69000320f481408455cf +F src/vdbe.h b02904e1bd45c26fdf00c04844b9cfa825763aa5150b6d89ce88b8ab03581d0a F src/vdbeInt.h bd589b8b7273286858950717e0e1ec5c88b18af45079a3366dc1371865cea704 F src/vdbeapi.c 95001d0f84ee3cda344fed98ca0d7961deb4fc836b83495630d0af1f7cc4789e -F src/vdbeaux.c a35a1785f980c44838b636a6d55a46b25ad80f2a2065851f165ab143aa46f99c +F src/vdbeaux.c a669f412027b6820cace9bf42e280c28304fc72bfc3475283ef33a5cce80e2e8 F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1 F src/vdbemem.c d8e10d1773806105e62094c4ede0a4684f46caaf07667a45e6d461e94306b530 F src/vdbesort.c a3be032cc3fee0e3af31773af4a7a6f931b7230a34f53282ccf1d9a2a72343be @@ -613,7 +613,7 @@ F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a F src/walker.c d5a94907dcac990e31976be9dc769d17f6a806782593d6aec9d760ee01ec22cd F src/where.c 9f3f23efc45934e7b7ea6c0c1042420b73053e7c3264feef6faf9ce6fbd5df61 F src/whereInt.h 2c6bae136a7c0be6ff75dc36950d1968c67d005c8e51d7a9d77cb996bb4843d9 -F src/wherecode.c 39df666a7281d3153b9f9d2cb04321cbb7cc403623a2862a292cb074e1b4a203 +F src/wherecode.c b9bb13fce68edf2eee56154a53adb923df7c0cf410fb319d0b2c4001c58a2c73 F src/whereexpr.c 05c283d26aa9c3f5d1bf13a5f6a573b43295b9db280eff18e26f97d7d7f119b4 F src/window.c 064f251451c8e2a1c76b6269229d911a651e119c6a5f522b6eaebf8dc8714041 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 450c48766c8e62653d074c95f69b0576de3880d183a1d1e5992d88b6fce6cc39 -R b12f2d235ff67ce42b63b55b4cb45601 +P 447271123e3b467d9271a4c0cf27f47af2f865c9298b8c355d9e766411a1f422 +R e46b1fe53b3eb28b7fe52d4e742c44d4 U drh -Z c0d073b04d67e49c297ac9c42fae3a3a +Z 941773dbc3af30d7e5e82c7718d2d1bf diff --git a/manifest.uuid b/manifest.uuid index d4b8a06657..a7110e869a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -447271123e3b467d9271a4c0cf27f47af2f865c9298b8c355d9e766411a1f422 \ No newline at end of file +e8426acb94179ff49549aced6ea3c26c49ba4761c2f414fa1772d6a031edc79d \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index 271bdbd482..e3a0abc2c0 100644 --- a/src/delete.c +++ b/src/delete.c @@ -475,13 +475,13 @@ void sqlite3DeleteFrom( if( pPk ){ for(i=0; iaiColumn[i]>=0 ); - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iTabCur, + sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, pPk->aiColumn[i], iPk+i); } iKey = iPk; }else{ iKey = ++pParse->nMem; - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iTabCur, -1, iKey); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, -1, iKey); } if( eOnePass!=ONEPASS_OFF ){ @@ -737,8 +737,7 @@ void sqlite3GenerateRowDelete( testcase( mask!=0xffffffff && iCol==31 ); testcase( mask!=0xffffffff && iCol==32 ); if( mask==0xffffffff || (iCol<=31 && (mask & MASKBIT32(iCol))!=0) ){ - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, iCol, - iOld+iCol+1); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+iCol+1); } } diff --git a/src/expr.c b/src/expr.c index c026c9583b..41ffe716ea 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3365,7 +3365,7 @@ void sqlite3ExprCodeLoadIndexColumn( sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut); pParse->iSelfTab = 0; }else{ - sqlite3ExprCodeGetColumnOfTable(pParse, pIdx->pTable, iTabCur, + sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur, iTabCol, regOut); } } @@ -3374,13 +3374,12 @@ void sqlite3ExprCodeLoadIndexColumn( ** Generate code to extract the value of the iCol-th column of a table. */ void sqlite3ExprCodeGetColumnOfTable( - Parse *pParse, /* Parsing context */ + Vdbe *v, /* Parsing context */ Table *pTab, /* The table containing the value */ int iTabCur, /* The table cursor. Or the PK cursor for WITHOUT ROWID */ int iCol, /* Index of the column to extract */ int regOut /* Extract the value into this register */ ){ - Vdbe *v = pParse->pVdbe; Column *pCol; assert( v!=0 ); if( pTab==0 ){ @@ -3397,6 +3396,7 @@ void sqlite3ExprCodeGetColumnOfTable( x = iCol; #ifndef SQLITE_OMIT_GENERATED_COLUMNS }else if( (pCol = &pTab->aCol[iCol])->colFlags & COLFLAG_VIRTUAL ){ + Parse *pParse = sqlite3VdbeParser(v); if( pCol->colFlags & COLFLAG_BUSY ){ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pCol->zName); }else{ @@ -3417,8 +3417,6 @@ void sqlite3ExprCodeGetColumnOfTable( op = OP_Column; } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); - } - if( iCol>=0 ){ sqlite3ColumnDefault(v, pTab, iCol, regOut); } } @@ -3439,7 +3437,7 @@ int sqlite3ExprCodeGetColumn( u8 p5 /* P5 value for OP_Column + FLAGS */ ){ assert( pParse->pVdbe!=0 ); - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iTable, iColumn, iReg); + sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg); if( p5 ){ sqlite3VdbeChangeP5(pParse->pVdbe, p5); } diff --git a/src/pragma.c b/src/pragma.c index 750ddb1404..8e2607e5a1 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1407,7 +1407,7 @@ void sqlite3Pragma( ** this case. */ for(j=0; jnCol; j++){ int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom; - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, 0, iCol, regRow+j); + sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j); sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); } @@ -1595,7 +1595,7 @@ void sqlite3Pragma( int jmp2; if( j==pTab->iPKey ) continue; if( pTab->aCol[j].notNull==0 ) continue; - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, j, 3); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, diff --git a/src/select.c b/src/select.c index f63ca06f4a..a5377a2c20 100644 --- a/src/select.c +++ b/src/select.c @@ -6417,7 +6417,7 @@ int sqlite3Select( struct AggInfo_col *pCol = &sAggInfo.aCol[i]; if( pCol->iSorterColumn>=j ){ int r1 = j + regBase; - sqlite3ExprCodeGetColumnOfTable(pParse, + sqlite3ExprCodeGetColumnOfTable(v, pCol->pTab, pCol->iTable, pCol->iColumn, r1); j++; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index f6646e4b82..2066ff5f82 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4077,7 +4077,7 @@ int sqlite3WhereOkOnePass(WhereInfo*, int*); #define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */ void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); -void sqlite3ExprCodeGetColumnOfTable(Parse*, Table*, int, int, int); +void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprCode(Parse*, Expr*, int); void sqlite3ExprCodeCopy(Parse*, Expr*, int); diff --git a/src/update.c b/src/update.c index 9b29757921..56ddec67bc 100644 --- a/src/update.c +++ b/src/update.c @@ -550,7 +550,7 @@ void sqlite3Update( ** is not required) and leave the PK fields in the array of registers. */ for(i=0; iaiColumn[i]>=0 ); - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i], iPk+i); } if( eOnePass ){ @@ -642,7 +642,7 @@ void sqlite3Update( || (colFlags & COLFLAG_PRIMKEY)!=0 ){ testcase( oldmask!=0xffffffff && i==31 ); - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, k); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, k); } @@ -685,7 +685,7 @@ void sqlite3Update( */ testcase( i==31 ); testcase( i==32 ); - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, k); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, k); } @@ -732,7 +732,7 @@ void sqlite3Update( if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--; }else if( aXRef[i]<0 && i!=pTab->iPKey ){ - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iDataCur, i, k); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k); } } #ifndef SQLITE_OMIT_GENERATED_COLUMNS diff --git a/src/vdbe.h b/src/vdbe.h index e3aaaa1ce2..5d53017f53 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -179,6 +179,7 @@ typedef struct VdbeOpList VdbeOpList; ** for a description of what each of these routines does. */ Vdbe *sqlite3VdbeCreate(Parse*); +Parse *sqlite3VdbeParser(Vdbe*); int sqlite3VdbeAddOp0(Vdbe*,int); int sqlite3VdbeAddOp1(Vdbe*,int,int); int sqlite3VdbeAddOp2(Vdbe*,int,int,int); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index c89b7d4197..c85bdc3874 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -42,6 +42,13 @@ Vdbe *sqlite3VdbeCreate(Parse *pParse){ return p; } +/* +** Return the Parse object that owns a Vdbe object. +*/ +Parse *sqlite3VdbeParser(Vdbe *p){ + return p->pParse; +} + /* ** Change the error string stored in Vdbe.zErrMsg */ diff --git a/src/wherecode.c b/src/wherecode.c index 39b9040db7..af395a3266 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -2072,7 +2072,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); if( HasRowid(pTab) ){ - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iCur, -1, regRowid); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, regRowid); jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, regRowid, iSet); VdbeCoverage(v); @@ -2086,7 +2086,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( r = sqlite3GetTempRange(pParse, nPk); for(iPk=0; iPkaiColumn[iPk]; - sqlite3ExprCodeGetColumnOfTable(pParse, pTab, iCur, iCol,r+iPk); + sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk); } /* Check if the temp table already contains this key. If so, From 8e10d74b214c1ff1bb542266c256f4a9ee3e9b47 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 18 Oct 2019 17:42:47 +0000 Subject: [PATCH 16/31] Get generated columns working for WITHOUT ROWID tables. FossilOrigin-Name: 9f409649ec4282a47f0a8b079b419f1922e0c24779b297f477ced168d5b7910d --- manifest | 18 ++++++------ manifest.uuid | 2 +- src/build.c | 75 +++++++++++++++++++++++++++++++++---------------- src/insert.c | 21 +++++++++++--- src/sqliteInt.h | 4 ++- src/where.c | 2 ++ 6 files changed, 83 insertions(+), 39 deletions(-) diff --git a/manifest b/manifest index 281510f5d9..685e339225 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Claw\sback\ssome\sperformance\sfrom\sthe\ssqlite3ExprGetColumnOfTable()\sroutine. -D 2019-10-18T12:52:08.655 +C Get\sgenerated\scolumns\sworking\sfor\sWITHOUT\sROWID\stables. +D 2019-10-18T17:42:47.815 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c 5e5fc50bda07b83d8f602218dae3099c9b7ee7b71d6d59dfa642dc074877ec35 +F src/build.c 1872ee2d0e09df69081ed25402b3e381d20df49981084d441e99e4dfe4d553fd F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 689b21b415d4bfe2a0ea2cf0066974d2a93899fa51af12453664214fa0d534e6 +F src/insert.c 6a9f9899469e3da1c2e50677fe34597c8315c7daa14f1b907872e598f40b7f13 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -530,7 +530,7 @@ F src/shell.c.in d70bcf630c4073eaa994fa74be98886c781918e794cb8b562be8df10f018e27 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h 769a3d9f244fe08c219aadc8474d180e3adca2c26cb5b13603adef4910b6ccf1 +F src/sqliteInt.h 9ccea3812a75ad6781fb113a4a5273ad0975ada4ed0e140542cc166b0edc34ca F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -611,7 +611,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c bbd6838bd79c0a32144d482fb0b6a9d2d1a252fb3b16d5005ec30f2f80413b0d F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a F src/walker.c d5a94907dcac990e31976be9dc769d17f6a806782593d6aec9d760ee01ec22cd -F src/where.c 9f3f23efc45934e7b7ea6c0c1042420b73053e7c3264feef6faf9ce6fbd5df61 +F src/where.c b7c662afaad3894b4a1ab60fe048b741705b5b4f6fa6dddbaa2fd7230404a4e8 F src/whereInt.h 2c6bae136a7c0be6ff75dc36950d1968c67d005c8e51d7a9d77cb996bb4843d9 F src/wherecode.c b9bb13fce68edf2eee56154a53adb923df7c0cf410fb319d0b2c4001c58a2c73 F src/whereexpr.c 05c283d26aa9c3f5d1bf13a5f6a573b43295b9db280eff18e26f97d7d7f119b4 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 447271123e3b467d9271a4c0cf27f47af2f865c9298b8c355d9e766411a1f422 -R e46b1fe53b3eb28b7fe52d4e742c44d4 +P e8426acb94179ff49549aced6ea3c26c49ba4761c2f414fa1772d6a031edc79d +R a1d17655d7716207219f9bae89301b1f U drh -Z 941773dbc3af30d7e5e82c7718d2d1bf +Z 8a3f73b128c9189e66135d5ce5fb6bf2 diff --git a/manifest.uuid b/manifest.uuid index a7110e869a..3afd9384c6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e8426acb94179ff49549aced6ea3c26c49ba4761c2f414fa1772d6a031edc79d \ No newline at end of file +9f409649ec4282a47f0a8b079b419f1922e0c24779b297f477ced168d5b7910d \ No newline at end of file diff --git a/src/build.c b/src/build.c index 3441e07779..1972915b7c 100644 --- a/src/build.c +++ b/src/build.c @@ -877,19 +877,11 @@ Index *sqlite3PrimaryKeyIndex(Table *pTab){ } /* -** Return the column of index pIdx that corresponds to table -** column iCol. Return -1 if not found. +** Return the true column number of index pIdx that corresponds to table +** true column iCol. Return -1 if not found. */ i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){ int i; -#ifndef SQLITE_OMIT_GENERATED_COLUMNS - Table *pTab = pIdx->pTable; - if( pTab->tabFlags & TF_HasVirtual ){ - for(i=0; i<=iCol; i++){ - if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) iCol++; - } - } -#endif for(i=0; inColumn; i++){ if( iCol==pIdx->aiColumn[i] ) return i; } @@ -897,13 +889,40 @@ i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){ } #ifndef SQLITE_OMIT_GENERATED_COLUMNS -/* -** Of the iCol-th column in table pTab, return the index of that column -** as stored on disk. Usually the return value is the same as the iCol -** input, however the return value may be less there are prior VIRTUAL -** columns. +/* Convert a storage column number into a true column number. ** -** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro +** The storage column number (0,1,2,....) is the index of the value +** as it appears in the record on disk. The true column number +** is the index (0,1,2,...) of the column in the CREATE TABLE statement. +** +** The storage column number is less than the true column number if +** and only there are virtual columns to the left. +** +** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro. +** +** This function is the inverse of sqlite3ColumnOfTable(). +*/ +i16 sqlite3ColumnOfStorage(Table *pTab, i16 iCol){ + if( pTab->tabFlags & TF_HasVirtual ){ + int i; + for(i=0; i<=iCol; i++){ + if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) iCol++; + } + } + return iCol; +} +#endif + +#ifndef SQLITE_OMIT_GENERATED_COLUMNS +/* Convert a true column number into a storage column number. +** +** The storage column number (0,1,2,....) is the index of the value +** as it appears in the record on disk. The true column number +** is the index (0,1,2,...) of the column in the CREATE TABLE statement. +** +** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro. +** +** This function is the inverse of sqlite3ColumnOfStorage(). */ i16 sqlite3ColumnOfTable(Table *pTab, i16 iCol){ int i; @@ -2050,11 +2069,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ */ nExtra = 0; for(i=0; inCol; i++){ - if( !hasColumn(pPk->aiColumn, nPk, i) ) nExtra++; + if( !hasColumn(pPk->aiColumn, nPk, i) + && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++; } if( resizeIndexObject(db, pPk, nPk+nExtra) ) return; for(i=0, j=nPk; inCol; i++){ - if( !hasColumn(pPk->aiColumn, j, i) ){ + if( !hasColumn(pPk->aiColumn, j, i) + && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 + ){ assert( jnColumn ); pPk->aiColumn[j] = i; pPk->azColl[j] = sqlite3StrBINARY; @@ -2062,7 +2084,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ } } assert( pPk->nColumn==j ); - assert( pTab->nCol<=j ); + assert( pTab->nNVCol<=j ); recomputeColumnsNotIndexed(pPk); } @@ -2172,14 +2194,11 @@ void sqlite3EndTable( } if( (p->tabFlags & TF_HasPrimaryKey)==0 ){ sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName); - }else{ - p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid; - convertToWithoutRowidTable(pParse, p); + return; } + p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid; } - iDb = sqlite3SchemaToIndex(db, p->pSchema); - #ifndef SQLITE_OMIT_CHECK /* Resolve names in all CHECK constraint expressions. */ @@ -2204,6 +2223,14 @@ void sqlite3EndTable( } #endif + /* Special processing for WITHOUT ROWID Tables */ + if( (tabOpts & TF_WithoutRowid)!=0 ){ + convertToWithoutRowidTable(pParse, p); + } + + iDb = sqlite3SchemaToIndex(db, p->pSchema); + + /* Estimate the average row size for the table and for all implied indices */ estimateTableWidth(p); for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ diff --git a/src/insert.c b/src/insert.c index f3bfeb4f60..d2e1efd5db 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1433,6 +1433,7 @@ void sqlite3GenerateConstraintChecks( /* Test all NOT NULL constraints. */ for(i=0; iiPKey ){ continue; /* ROWID is never NULL */ } @@ -1453,14 +1454,26 @@ void sqlite3GenerateConstraintChecks( assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); addr1 = 0; + if( (pTab->tabFlags & TF_HasVirtual)==0 ){ + iReg = regNewData+1+i; + }else if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ + iReg = ++pParse->nMem; + assert( pParse->iSelfTab==0 ); + pParse->iSelfTab = -regNewData; + sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iReg); + pParse->iSelfTab = 0; + if( onError==OE_Replace ) onError = OE_Abort; + }else{ + iReg = sqlite3ColumnOfTable(pTab, i) + regNewData + 1; + } switch( onError ){ case OE_Replace: { assert( onError==OE_Replace ); addr1 = sqlite3VdbeMakeLabel(pParse); - sqlite3VdbeAddOp2(v, OP_NotNull, regNewData+1+i, addr1); + sqlite3VdbeAddOp2(v, OP_NotNull, iReg, addr1); VdbeCoverage(v); sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i); - sqlite3VdbeAddOp2(v, OP_NotNull, regNewData+1+i, addr1); + sqlite3VdbeAddOp2(v, OP_NotNull, iReg, addr1); VdbeCoverage(v); onError = OE_Abort; /* Fall through into the OE_Abort case to generate code that runs @@ -1474,7 +1487,7 @@ void sqlite3GenerateConstraintChecks( char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, pTab->aCol[i].zName); sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, - regNewData+1+i); + iReg); sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); sqlite3VdbeChangeP5(v, P5_ConstraintNotNull); VdbeCoverage(v); @@ -1483,7 +1496,7 @@ void sqlite3GenerateConstraintChecks( } default: { assert( onError==OE_Ignore ); - sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest); + sqlite3VdbeAddOp2(v, OP_IsNull, iReg, ignoreDest); VdbeCoverage(v); break; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 2066ff5f82..a1e6e175bb 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3954,9 +3954,11 @@ void sqlite3OpenMasterTable(Parse *, int); Index *sqlite3PrimaryKeyIndex(Table*); i16 sqlite3ColumnOfIndex(Index*, i16); #ifdef SQLITE_OMIT_GENERATED_COLUMNS -# define sqlite3ColumnOfTable(T,X) (X) /* No-op pass-through */ +# define sqlite3ColumnOfTable(T,X) (X) /* No-op pass-through */ +# define sqlite3ColumnOfStorage(T,X) (X) /* No-op pass-through */ #else i16 sqlite3ColumnOfTable(Table*, i16); + i16 sqlite3ColumnOfStorage(Table*, i16); #endif void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); #if SQLITE_ENABLE_HIDDEN_COLUMNS diff --git a/src/where.c b/src/where.c index 1a43b8d19e..252e90665c 100644 --- a/src/where.c +++ b/src/where.c @@ -5378,6 +5378,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ Index *pPk = sqlite3PrimaryKeyIndex(pTab); x = pPk->aiColumn[x]; assert( x>=0 ); + }else{ + x = sqlite3ColumnOfStorage(pTab,x); } x = sqlite3ColumnOfIndex(pIdx, x); if( x>=0 ){ From f95909c7648942e7157722c33b5e5f9293bf3436 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 18 Oct 2019 18:33:25 +0000 Subject: [PATCH 17/31] Fixes for WITHOUT ROWID tables with VIRTUAL columns and an INTEGER PRIMARY KEY. FossilOrigin-Name: 86074da0fd2949e231898ef0bc672d90fd89cefa49fb0eb50ff398fbdd91d1ad --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/build.c | 17 ++++------------- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index ec1a5b3065..74c780e22f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\strunk\senhancements\sinto\sthe\sgenerated-columns\sbranch. -D 2019-10-18T17:47:47.787 +C Fixes\sfor\sWITHOUT\sROWID\stables\swith\sVIRTUAL\scolumns\sand\san\sINTEGER\sPRIMARY\sKEY. +D 2019-10-18T18:33:25.975 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c 1872ee2d0e09df69081ed25402b3e381d20df49981084d441e99e4dfe4d553fd +F src/build.c c38f1b8942572cecf2b9e4abb6984be73ebb6c5c0fdd91c776734d73460fcaf8 F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 9f409649ec4282a47f0a8b079b419f1922e0c24779b297f477ced168d5b7910d 9dc0d34586eebf6705d9bd81494c417ac76707b8625d1ff99eda18b4ca2d8a50 -R 8ebd80e22c07677946c96a01428911bf +P 85bc4524d76999080faa4474e8880d2b6a2ac3a7f6a76239af4de1a42f8138c8 +R 0af80221f2d400634eaa464ec81f7f65 U drh -Z 73fa86e472de993d3352f53eb78454b7 +Z f141c57ae5a92a7a4189b1c5f348b449 diff --git a/manifest.uuid b/manifest.uuid index 5cd80d372b..d0d7b9d0ae 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -85bc4524d76999080faa4474e8880d2b6a2ac3a7f6a76239af4de1a42f8138c8 \ No newline at end of file +86074da0fd2949e231898ef0bc672d90fd89cefa49fb0eb50ff398fbdd91d1ad \ No newline at end of file diff --git a/src/build.c b/src/build.c index 1972915b7c..f00dc32ad0 100644 --- a/src/build.c +++ b/src/build.c @@ -1226,6 +1226,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){ pCol->colFlags |= COLFLAG_HASTYPE; } p->nCol++; + p->nNVCol++; pParse->constraintName.n = 0; } @@ -1591,6 +1592,7 @@ void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ goto generated_error; } } + if( eType==COLFLAG_VIRTUAL ) pTab->nNVCol--; pCol->colFlags |= eType; assert( TF_HasVirtual==COLFLAG_VIRTUAL ); assert( TF_HasStored==COLFLAG_STORED ); @@ -2156,7 +2158,6 @@ void sqlite3EndTable( assert( !db->mallocFailed ); p = pParse->pNewTable; if( p==0 ) return; - p->nNVCol = p->nCol; if( pSelect==0 && isShadowTableName(db, p->zName) ){ p->tabFlags |= TF_Shadow; @@ -2197,7 +2198,9 @@ void sqlite3EndTable( return; } p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid; + convertToWithoutRowidTable(pParse, p); } + iDb = sqlite3SchemaToIndex(db, p->pSchema); #ifndef SQLITE_OMIT_CHECK /* Resolve names in all CHECK constraint expressions. @@ -2212,10 +2215,6 @@ void sqlite3EndTable( for(ii=0; iinCol; ii++){ u32 colFlags = p->aCol[ii].colFlags; if( (colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL))!=0 ){ - if( colFlags & COLFLAG_VIRTUAL ){ - p->nNVCol--; - assert( p->nNVCol>=0 ); - } sqlite3ResolveSelfReference(pParse, p, NC_GenCol, p->aCol[ii].pDflt, 0); } @@ -2223,14 +2222,6 @@ void sqlite3EndTable( } #endif - /* Special processing for WITHOUT ROWID Tables */ - if( (tabOpts & TF_WithoutRowid)!=0 ){ - convertToWithoutRowidTable(pParse, p); - } - - iDb = sqlite3SchemaToIndex(db, p->pSchema); - - /* Estimate the average row size for the table and for all implied indices */ estimateTableWidth(p); for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){ From b9bcf7ca600ab8a94018adc2eac4115441a09d89 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 19 Oct 2019 13:29:10 +0000 Subject: [PATCH 18/31] Refactor names of column index transformation functions, for clarity. Get generated columns working with ALTER TABLE RENAME COLUMN. FossilOrigin-Name: 27ab41c9102e7801ff829488fc123a8040da008bef373d6704efbe2f93e1da90 --- manifest | 30 +++++++++++++++--------------- manifest.uuid | 2 +- src/alter.c | 5 +++++ src/analyze.c | 2 +- src/build.c | 38 +++++++++++++++++++++----------------- src/expr.c | 9 +++++---- src/insert.c | 8 ++++---- src/sqliteInt.h | 27 ++++++++++++++++++++------- src/upsert.c | 2 +- src/vdbeapi.c | 4 ++-- src/where.c | 4 ++-- src/wherecode.c | 6 +++--- 12 files changed, 80 insertions(+), 57 deletions(-) diff --git a/manifest b/manifest index 74c780e22f..8ebde088c2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fixes\sfor\sWITHOUT\sROWID\stables\swith\sVIRTUAL\scolumns\sand\san\sINTEGER\sPRIMARY\sKEY. -D 2019-10-18T18:33:25.975 +C Refactor\snames\sof\scolumn\sindex\stransformation\sfunctions,\sfor\sclarity.\nGet\sgenerated\scolumns\sworking\swith\sALTER\sTABLE\sRENAME\sCOLUMN. +D 2019-10-19T13:29:10.933 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -459,8 +459,8 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c 8a4317e2b322d4da9489cf2aa1d513a3a6f3e4863552dd5e59d08cdaca73c487 -F src/analyze.c 481d9cf34a3c70631ef5c416be70033e8d4cd85eb5ad1b37286aed8b0e29e889 +F src/alter.c fa7486bfd12be8c8a0d4425767fa42203ca9e946c9613bb37924643c622706bf +F src/analyze.c fd70b9c7a683230a7f7936af64dd25308e93d7c9819a3168493a7c7703481f80 F src/attach.c 3ca19504849c2d9be10fc5899d6811f9d6e848665d1a41ffb53df0cd6e7c13ed F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 F src/backup.c f70077d40c08b7787bfe934e4d1da8030cb0cc57d46b345fba2294b7d1be23ab @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c c38f1b8942572cecf2b9e4abb6984be73ebb6c5c0fdd91c776734d73460fcaf8 +F src/build.c fb6464e8ae5364a7a31915432f349d209a1a3fd287edbce651600bf46ccacd34 F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -477,7 +477,7 @@ F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319 F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf -F src/expr.c e2c2f78c9f63de2bedabf34f8f25968c6b2317313d1ef15a37c8aa9bd29dcf75 +F src/expr.c 8caa6f07be582979dec421beda6b77033f9b50f97bb1844e189f920a41b781ee F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 6271fda51794b569d736eba4097d28f13080cd0c9eb66d5fcecb4b77336fae50 F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 1e565be06343e9d24a6c4f82023e5b0ffb0358c41fb4fb28f95fe50c9f9727b4 +F src/insert.c 66662a52c4e205dbaeb318591bf2aaf1b957920003d1911c6a0dce6dfaad1eed F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -530,7 +530,7 @@ F src/shell.c.in 3093bdf5eedd91da08f0268f1442aa510a60798c9441868149ddbecdf8bcaa7 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h 9ccea3812a75ad6781fb113a4a5273ad0975ada4ed0e140542cc166b0edc34ca +F src/sqliteInt.h 7fa9357635e6c32c61d103054a4d4040392d81a798cfe982c09d4ed5568aa724 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -593,14 +593,14 @@ F src/tokenize.c 7b17f6e2f20f6cbcb0b215025a86b7457c38451fc7622f705e553d7a488c572 F src/treeview.c fddeb413159c3eeeaea3f496172f121cf3695606c461dc4e6dcee51417952df5 F src/trigger.c 845ccc08f60716c58aa28fe6470385c18ef8c4e1d88c93dcf449bc13d464eb2e F src/update.c ca754bbcb5662184bf5face4b67686bed8f53a36cf3def87cbb238deb1086b9b -F src/upsert.c 710c91bb13e3c3fed5b6fe17cb13e09560bdd003ad8b8c51e6b16c80cfc48b10 +F src/upsert.c b445315c8958d8f17ec3297d06842e61dacaad0633ccaec1e4e160de7e562212 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507 F src/util.c 10d910e04a4f3842042485e0df01a484f57f912c10b60b3a09ccddd5019bd138 F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf F src/vdbe.c 9a3f4c2ec6c45e4bd5db465e77e79dfdf5bdc5cf3a8c0bfe9549da209b9c18bc F src/vdbe.h b02904e1bd45c26fdf00c04844b9cfa825763aa5150b6d89ce88b8ab03581d0a F src/vdbeInt.h bd589b8b7273286858950717e0e1ec5c88b18af45079a3366dc1371865cea704 -F src/vdbeapi.c 95001d0f84ee3cda344fed98ca0d7961deb4fc836b83495630d0af1f7cc4789e +F src/vdbeapi.c 1252d80c548711e47a6d84dae88ed4e95d3fbb4e7bd0eaa1347299af7efddf02 F src/vdbeaux.c a669f412027b6820cace9bf42e280c28304fc72bfc3475283ef33a5cce80e2e8 F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1 F src/vdbemem.c d8e10d1773806105e62094c4ede0a4684f46caaf07667a45e6d461e94306b530 @@ -611,9 +611,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c bbd6838bd79c0a32144d482fb0b6a9d2d1a252fb3b16d5005ec30f2f80413b0d F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a F src/walker.c d5a94907dcac990e31976be9dc769d17f6a806782593d6aec9d760ee01ec22cd -F src/where.c b7c662afaad3894b4a1ab60fe048b741705b5b4f6fa6dddbaa2fd7230404a4e8 +F src/where.c 7b2d928b70ac885fb63c871e97d3502f3e0fbe14ec605ba05675d03f20aa6c5e F src/whereInt.h 2c6bae136a7c0be6ff75dc36950d1968c67d005c8e51d7a9d77cb996bb4843d9 -F src/wherecode.c b9bb13fce68edf2eee56154a53adb923df7c0cf410fb319d0b2c4001c58a2c73 +F src/wherecode.c d96190c0b536339375846048ad3c41758b4bd6baaf8f8f350da5911d42bc4a61 F src/whereexpr.c 05c283d26aa9c3f5d1bf13a5f6a573b43295b9db280eff18e26f97d7d7f119b4 F src/window.c 064f251451c8e2a1c76b6269229d911a651e119c6a5f522b6eaebf8dc8714041 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 85bc4524d76999080faa4474e8880d2b6a2ac3a7f6a76239af4de1a42f8138c8 -R 0af80221f2d400634eaa464ec81f7f65 +P 86074da0fd2949e231898ef0bc672d90fd89cefa49fb0eb50ff398fbdd91d1ad +R 72d8383f6985e8f8ce5ac07723f6738a U drh -Z f141c57ae5a92a7a4189b1c5f348b449 +Z 25261f5626aab97bfd8acba5a24fa871 diff --git a/manifest.uuid b/manifest.uuid index d0d7b9d0ae..9b4c67a7fe 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -86074da0fd2949e231898ef0bc672d90fd89cefa49fb0eb50ff398fbdd91d1ad \ No newline at end of file +27ab41c9102e7801ff829488fc123a8040da008bef373d6704efbe2f93e1da90 \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index f8cada0e34..b7389bf9cb 100644 --- a/src/alter.c +++ b/src/alter.c @@ -1334,6 +1334,11 @@ static void renameColumnFunc( sqlite3WalkExprList(&sWalker, pIdx->aColExpr); } } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + for(i=0; inCol; i++){ + sqlite3WalkExpr(&sWalker, sParse.pNewTable->aCol[i].pDflt); + } +#endif for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){ for(i=0; inCol; i++){ diff --git a/src/analyze.c b/src/analyze.c index 8f73853c85..6df6e7a6ec 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -1182,7 +1182,7 @@ static void analyzeOneTable( int j, k, regKey; regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; jnKeyCol; j++){ - k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); + k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]); assert( k>=0 && knColumn ); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j); VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName)); diff --git a/src/build.c b/src/build.c index f00dc32ad0..48f3a1c1ea 100644 --- a/src/build.c +++ b/src/build.c @@ -877,10 +877,12 @@ Index *sqlite3PrimaryKeyIndex(Table *pTab){ } /* -** Return the true column number of index pIdx that corresponds to table -** true column iCol. Return -1 if not found. +** Convert an table column number into a index column number. That is, +** for the column iCol in the table (as defined by the CREATE TABLE statement) +** find the (first) offset of that column in index pIdx. Or return -1 +** if column iCol is not used in index pIdx. */ -i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){ +i16 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){ int i; for(i=0; inColumn; i++){ if( iCol==pIdx->aiColumn[i] ) return i; @@ -889,20 +891,20 @@ i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){ } #ifndef SQLITE_OMIT_GENERATED_COLUMNS -/* Convert a storage column number into a true column number. +/* Convert a storage column number into a table column number. ** ** The storage column number (0,1,2,....) is the index of the value ** as it appears in the record on disk. The true column number ** is the index (0,1,2,...) of the column in the CREATE TABLE statement. ** -** The storage column number is less than the true column number if -** and only there are virtual columns to the left. +** The storage column number is less than the table column number if +** and only there are VIRTUAL columns to the left. ** ** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro. ** -** This function is the inverse of sqlite3ColumnOfTable(). +** This function is the inverse of sqlite3TableColumnToStorage(). */ -i16 sqlite3ColumnOfStorage(Table *pTab, i16 iCol){ +i16 sqlite3StorageColumnToTable(Table *pTab, i16 iCol){ if( pTab->tabFlags & TF_HasVirtual ){ int i; for(i=0; i<=iCol; i++){ @@ -914,7 +916,7 @@ i16 sqlite3ColumnOfStorage(Table *pTab, i16 iCol){ #endif #ifndef SQLITE_OMIT_GENERATED_COLUMNS -/* Convert a true column number into a storage column number. +/* Convert a table column number into a storage column number. ** ** The storage column number (0,1,2,....) is the index of the value ** as it appears in the record on disk. The true column number @@ -922,9 +924,9 @@ i16 sqlite3ColumnOfStorage(Table *pTab, i16 iCol){ ** ** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro. ** -** This function is the inverse of sqlite3ColumnOfStorage(). +** This function is the inverse of sqlite3StorageColumnToTable(). */ -i16 sqlite3ColumnOfTable(Table *pTab, i16 iCol){ +i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){ int i; i16 n; assert( iColnCol ); @@ -1577,11 +1579,12 @@ void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ u8 eType = COLFLAG_VIRTUAL; Table *pTab = pParse->pNewTable; Column *pCol; - if( IN_RENAME_OBJECT ){ - sqlite3RenameExprUnmap(pParse, pExpr); - } if( pTab==0 ) goto generated_done; pCol = &(pTab->aCol[pTab->nCol-1]); + if( IN_DECLARE_VTAB ){ + sqlite3ErrorMsg(pParse, "virtual tables cannot use computed columns"); + goto generated_done; + } if( pCol->pDflt ) goto generated_error; if( pType ){ if( pType->n==7 && sqlite3StrNICmp("virtual",pType->z,7)==0 ){ @@ -1597,7 +1600,8 @@ void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ assert( TF_HasVirtual==COLFLAG_VIRTUAL ); assert( TF_HasStored==COLFLAG_STORED ); pTab->tabFlags |= eType; - pCol->pDflt = sqlite3ExprDup(pParse->db, pExpr, 0); + pCol->pDflt = pExpr; + pExpr = 0; goto generated_done; generated_error: @@ -3651,13 +3655,13 @@ void sqlite3CreateIndex( /* If this index contains every column of its table, then mark ** it as a covering index */ assert( HasRowid(pTab) - || pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 ); + || pTab->iPKey<0 || sqlite3TableColumnToIndex(pIndex, pTab->iPKey)>=0 ); recomputeColumnsNotIndexed(pIndex); if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){ pIndex->isCovering = 1; for(j=0; jnCol; j++){ if( j==pTab->iPKey ) continue; - if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue; + if( sqlite3TableColumnToIndex(pIndex,j)>=0 ) continue; pIndex->isCovering = 0; break; } diff --git a/src/expr.c b/src/expr.c index 41ffe716ea..c57a0000d5 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3410,10 +3410,10 @@ void sqlite3ExprCodeGetColumnOfTable( return; #endif }else if( !HasRowid(pTab) ){ - x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol); + x = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), iCol); op = OP_Column; }else{ - x = sqlite3ColumnOfTable(pTab,iCol); + x = sqlite3TableColumnToStorage(pTab,iCol); op = OP_Column; } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); @@ -3591,7 +3591,8 @@ expr_code_doover: return -1-pParse->iSelfTab; } pCol = pTab->aCol + pExpr->iColumn; - iSrc = sqlite3ColumnOfTable(pTab, pExpr->iColumn) - pParse->iSelfTab; + iSrc = sqlite3TableColumnToStorage(pTab, pExpr->iColumn) + - pParse->iSelfTab; #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( pCol->colFlags & COLFLAG_GENERATED ){ if( pCol->colFlags & COLFLAG_BUSY ){ @@ -5320,7 +5321,7 @@ struct IdxCover { static int exprIdxCover(Walker *pWalker, Expr *pExpr){ if( pExpr->op==TK_COLUMN && pExpr->iTable==pWalker->u.pIdxCover->iCur - && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0 + && sqlite3TableColumnToIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0 ){ pWalker->eCode = 1; return WRC_Abort; diff --git a/src/insert.c b/src/insert.c index fe275d5a01..88b8e6ad26 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1055,7 +1055,7 @@ void sqlite3Insert( int k; u32 colFlags; assert( i>=nHidden ); - assert( iRegStore==sqlite3ColumnOfTable(pTab,i)+regRowid+1 ); + assert( iRegStore==sqlite3TableColumnToStorage(pTab,i)+regRowid+1 ); if( i==pTab->iPKey ){ /* The value of the INTEGER PRIMARY KEY column is always a NULL. ** Whenever this column is read, the rowid will be substituted @@ -1464,7 +1464,7 @@ void sqlite3GenerateConstraintChecks( pParse->iSelfTab = 0; if( onError==OE_Replace ) onError = OE_Abort; }else{ - iReg = sqlite3ColumnOfTable(pTab, i) + regNewData + 1; + iReg = sqlite3TableColumnToStorage(pTab, i) + regNewData + 1; } switch( onError ){ case OE_Replace: { @@ -1782,7 +1782,7 @@ void sqlite3GenerateConstraintChecks( VdbeComment((v, "%s column %d", pIdx->zName, i)); #endif }else{ - x = sqlite3ColumnOfTable(pTab, iField) + regNewData + 1; + x = sqlite3TableColumnToStorage(pTab, iField) + regNewData + 1; sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); VdbeComment((v, "%s", pTab->aCol[iField].zName)); } @@ -1873,7 +1873,7 @@ void sqlite3GenerateConstraintChecks( if( pIdx!=pPk ){ for(i=0; inKeyCol; i++){ assert( pPk->aiColumn[i]>=0 ); - x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]); + x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]); sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i); VdbeComment((v, "%s.%s", pTab->zName, pTab->aCol[pPk->aiColumn[i]].zName)); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a1e6e175bb..10b2eeaf3f 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1818,8 +1818,21 @@ struct Module { }; /* -** information about each column of an SQL table is held in an instance -** of this structure. +** Information about each column of an SQL table is held in an instance +** of the Column structure, in the Table.aCol[] array. +** +** Definitions: +** +** "table column index" This is the index of the column in the +** Table.aCol[] array, and also the index of +** the column in the original CREATE TABLE stmt. +** +** "storage column index" This is the index of the column in the +** record BLOB generated by the OP_MakeRecord +** opcode. The storage column index is less than +** or equal to the table column index. It is +** equal if and only if there are no VIRTUAL +** columns to the left. */ struct Column { char *zName; /* Name of this column, \000, then the type */ @@ -3952,13 +3965,13 @@ void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char); Table *sqlite3ResultSetOfSelect(Parse*,Select*,char); void sqlite3OpenMasterTable(Parse *, int); Index *sqlite3PrimaryKeyIndex(Table*); -i16 sqlite3ColumnOfIndex(Index*, i16); +i16 sqlite3TableColumnToIndex(Index*, i16); #ifdef SQLITE_OMIT_GENERATED_COLUMNS -# define sqlite3ColumnOfTable(T,X) (X) /* No-op pass-through */ -# define sqlite3ColumnOfStorage(T,X) (X) /* No-op pass-through */ +# define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */ +# define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */ #else - i16 sqlite3ColumnOfTable(Table*, i16); - i16 sqlite3ColumnOfStorage(Table*, i16); + i16 sqlite3TableColumnToStorage(Table*, i16); + i16 sqlite3StorageColumnToTable(Table*, i16); #endif void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); #if SQLITE_ENABLE_HIDDEN_COLUMNS diff --git a/src/upsert.c b/src/upsert.c index 7beb9ffaec..5db4f5fc90 100644 --- a/src/upsert.c +++ b/src/upsert.c @@ -226,7 +226,7 @@ void sqlite3UpsertDoUpdate( for(i=0; iaiColumn[i]>=0 ); - k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]); + k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]); sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i); VdbeComment((v, "%s.%s", pIdx->zName, pTab->aCol[pPk->aiColumn[i]].zName)); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index c7968ee60d..074d458815 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1831,7 +1831,7 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ goto preupdate_old_out; } if( p->pPk ){ - iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx); + iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); } if( iIdx>=p->pCsr->nField || iIdx<0 ){ rc = SQLITE_RANGE; @@ -1921,7 +1921,7 @@ int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){ goto preupdate_new_out; } if( p->pPk && p->op!=SQLITE_UPDATE ){ - iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx); + iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx); } if( iIdx>=p->pCsr->nField || iIdx<0 ){ rc = SQLITE_RANGE; diff --git a/src/where.c b/src/where.c index 252e90665c..ec2d3847b7 100644 --- a/src/where.c +++ b/src/where.c @@ -5379,9 +5379,9 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ x = pPk->aiColumn[x]; assert( x>=0 ); }else{ - x = sqlite3ColumnOfStorage(pTab,x); + x = sqlite3StorageColumnToTable(pTab,x); } - x = sqlite3ColumnOfIndex(pIdx, x); + x = sqlite3TableColumnToIndex(pIdx, x); if( x>=0 ){ pOp->p2 = x; pOp->p1 = pLevel->iIdxCur; diff --git a/src/wherecode.c b/src/wherecode.c index af395a3266..686a8d6f9a 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -823,7 +823,7 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){ assert( pHint->pIdx!=0 ); if( pExpr->op==TK_COLUMN && pExpr->iTable==pHint->iTabCur - && sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn)<0 + && sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn)<0 ){ pWalker->eCode = 1; } @@ -891,7 +891,7 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ pExpr->iTable = reg; }else if( pHint->pIdx!=0 ){ pExpr->iTable = pHint->iIdxCur; - pExpr->iColumn = sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn); + pExpr->iColumn = sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn); assert( pExpr->iColumn>=0 ); } }else if( pExpr->op==TK_AGG_FUNCTION ){ @@ -1826,7 +1826,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; jnKeyCol; j++){ - k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); + k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j); } sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont, From c5f808d85ef130717aee1bc7e7ffcd934c84ab66 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 19 Oct 2019 15:01:52 +0000 Subject: [PATCH 19/31] Add testcase macros. FossilOrigin-Name: fb9c9bb284d441bd7aa34c87b6fd8ce57d036c17623d82354154fc6286bdd134 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/expr.c | 15 +++++++++------ src/insert.c | 2 ++ src/where.c | 1 + 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index 8ebde088c2..729ea94862 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Refactor\snames\sof\scolumn\sindex\stransformation\sfunctions,\sfor\sclarity.\nGet\sgenerated\scolumns\sworking\swith\sALTER\sTABLE\sRENAME\sCOLUMN. -D 2019-10-19T13:29:10.933 +C Add\stestcase\smacros. +D 2019-10-19T15:01:52.518 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -477,7 +477,7 @@ F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319 F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf -F src/expr.c 8caa6f07be582979dec421beda6b77033f9b50f97bb1844e189f920a41b781ee +F src/expr.c 254252a94890f2493a5e214971342bfdf228857483ea7a263ae75048ff67f5b5 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 6271fda51794b569d736eba4097d28f13080cd0c9eb66d5fcecb4b77336fae50 F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 66662a52c4e205dbaeb318591bf2aaf1b957920003d1911c6a0dce6dfaad1eed +F src/insert.c 2f1b93da19a9a65eab197534dcc3fb569708b1a7035da5b229063b7f13e71253 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -611,7 +611,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c bbd6838bd79c0a32144d482fb0b6a9d2d1a252fb3b16d5005ec30f2f80413b0d F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a F src/walker.c d5a94907dcac990e31976be9dc769d17f6a806782593d6aec9d760ee01ec22cd -F src/where.c 7b2d928b70ac885fb63c871e97d3502f3e0fbe14ec605ba05675d03f20aa6c5e +F src/where.c 9ab206102932b7fe0e05f8e9133b5c0a351c0fd6f01e5d65ae4d1cd116aa89e6 F src/whereInt.h 2c6bae136a7c0be6ff75dc36950d1968c67d005c8e51d7a9d77cb996bb4843d9 F src/wherecode.c d96190c0b536339375846048ad3c41758b4bd6baaf8f8f350da5911d42bc4a61 F src/whereexpr.c 05c283d26aa9c3f5d1bf13a5f6a573b43295b9db280eff18e26f97d7d7f119b4 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 86074da0fd2949e231898ef0bc672d90fd89cefa49fb0eb50ff398fbdd91d1ad -R 72d8383f6985e8f8ce5ac07723f6738a +P 27ab41c9102e7801ff829488fc123a8040da008bef373d6704efbe2f93e1da90 +R 72df5515bebd9dc031bf51cf11383344 U drh -Z 25261f5626aab97bfd8acba5a24fa871 +Z dca30fedc0b8883c88ac3723c3316cd7 diff --git a/manifest.uuid b/manifest.uuid index 9b4c67a7fe..7c08b6a36c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -27ab41c9102e7801ff829488fc123a8040da008bef373d6704efbe2f93e1da90 \ No newline at end of file +fb9c9bb284d441bd7aa34c87b6fd8ce57d036c17623d82354154fc6286bdd134 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index c57a0000d5..01e99428f3 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3410,10 +3410,12 @@ void sqlite3ExprCodeGetColumnOfTable( return; #endif }else if( !HasRowid(pTab) ){ + testcase( iCol!=sqlite3TableColumnToStorage(pTab, iCol) ); x = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), iCol); op = OP_Column; }else{ x = sqlite3TableColumnToStorage(pTab,iCol); + testcase( x!=iCol ); op = OP_Column; } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); @@ -3584,15 +3586,16 @@ expr_code_doover: Column *pCol; Table *pTab = pExpr->y.pTab; int iSrc; + int iCol = pExpr->iColumn; assert( pTab!=0 ); - assert( pExpr->iColumn>=XN_ROWID ); - assert( pExpr->iColumny.pTab->nCol ); - if( pExpr->iColumn<0 ){ + assert( iCol>=XN_ROWID ); + assert( iColy.pTab->nCol ); + if( iCol<0 ){ return -1-pParse->iSelfTab; } - pCol = pTab->aCol + pExpr->iColumn; - iSrc = sqlite3TableColumnToStorage(pTab, pExpr->iColumn) - - pParse->iSelfTab; + pCol = pTab->aCol + iCol; + testcase( iCol!=sqlite3TableColumnToStorage(pTab,iCol) ); + iSrc = sqlite3TableColumnToStorage(pTab, iCol) - pParse->iSelfTab; #ifndef SQLITE_OMIT_GENERATED_COLUMNS if( pCol->colFlags & COLFLAG_GENERATED ){ if( pCol->colFlags & COLFLAG_BUSY ){ diff --git a/src/insert.c b/src/insert.c index 88b8e6ad26..e15e9feed2 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1464,6 +1464,7 @@ void sqlite3GenerateConstraintChecks( pParse->iSelfTab = 0; if( onError==OE_Replace ) onError = OE_Abort; }else{ + testcase( i!=sqlite3TableColumnToStorage(pTab, i) ); iReg = sqlite3TableColumnToStorage(pTab, i) + regNewData + 1; } switch( onError ){ @@ -1782,6 +1783,7 @@ void sqlite3GenerateConstraintChecks( VdbeComment((v, "%s column %d", pIdx->zName, i)); #endif }else{ + testcase( sqlite3TableColumnToStorage(pTab, iField)!=iField ); x = sqlite3TableColumnToStorage(pTab, iField) + regNewData + 1; sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); VdbeComment((v, "%s", pTab->aCol[iField].zName)); diff --git a/src/where.c b/src/where.c index ec2d3847b7..dc2b463f28 100644 --- a/src/where.c +++ b/src/where.c @@ -5379,6 +5379,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ x = pPk->aiColumn[x]; assert( x>=0 ); }else{ + testcase( x!=sqlite3StorageColumnToTable(pTab,x) ); x = sqlite3StorageColumnToTable(pTab,x); } x = sqlite3TableColumnToIndex(pIdx, x); From dd6cc9b52abf6c4ae15a57a9f3d6e3c1e848f589 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 19 Oct 2019 18:47:27 +0000 Subject: [PATCH 20/31] Work toward getting generated columns to work with triggers. Still more work to do in this area. FossilOrigin-Name: 932a37275d7e932f8237d32c8fc6087ed8cd342fe01ef2f7a43c7237ab84c9ac --- manifest | 20 ++++++++-------- manifest.uuid | 2 +- src/build.c | 42 +++++++++++++++++++++++++++------ src/expr.c | 25 ++++++++------------ src/insert.c | 63 ++++++++++++++++++++++++------------------------- src/sqliteInt.h | 2 +- src/update.c | 8 +++---- 7 files changed, 92 insertions(+), 70 deletions(-) diff --git a/manifest b/manifest index 729ea94862..2d2a9b70e5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stestcase\smacros. -D 2019-10-19T15:01:52.518 +C Work\stoward\sgetting\sgenerated\scolumns\sto\swork\swith\striggers.\s\sStill\smore\nwork\sto\sdo\sin\sthis\sarea. +D 2019-10-19T18:47:27.679 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c fb6464e8ae5364a7a31915432f349d209a1a3fd287edbce651600bf46ccacd34 +F src/build.c c6421066f1ce6ce789a8346818f7ce00fec47f469004fa6b6d31643d793d2b2d F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -477,7 +477,7 @@ F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319 F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf -F src/expr.c 254252a94890f2493a5e214971342bfdf228857483ea7a263ae75048ff67f5b5 +F src/expr.c ffa1cda4277078c0572055f46f83d06dc2e0a89b843e601bef6f9dc8fd430f41 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 6271fda51794b569d736eba4097d28f13080cd0c9eb66d5fcecb4b77336fae50 F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 2f1b93da19a9a65eab197534dcc3fb569708b1a7035da5b229063b7f13e71253 +F src/insert.c fd8ba5c85b6e96770957f3f23b66fb619adb287dcd53e6f19fb5e8ddaf9b792a F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -530,7 +530,7 @@ F src/shell.c.in 3093bdf5eedd91da08f0268f1442aa510a60798c9441868149ddbecdf8bcaa7 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h 7fa9357635e6c32c61d103054a4d4040392d81a798cfe982c09d4ed5568aa724 +F src/sqliteInt.h 1929d5f85ce9e4aba60540c70f88ef6fcd2bb272ee52b7dfee96126775dd12b9 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -592,7 +592,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c 7b17f6e2f20f6cbcb0b215025a86b7457c38451fc7622f705e553d7a488c572d F src/treeview.c fddeb413159c3eeeaea3f496172f121cf3695606c461dc4e6dcee51417952df5 F src/trigger.c 845ccc08f60716c58aa28fe6470385c18ef8c4e1d88c93dcf449bc13d464eb2e -F src/update.c ca754bbcb5662184bf5face4b67686bed8f53a36cf3def87cbb238deb1086b9b +F src/update.c e5c432097191e6e6c73e48364daa58b257b30a8b0d54b018fd0bd9415cd7b553 F src/upsert.c b445315c8958d8f17ec3297d06842e61dacaad0633ccaec1e4e160de7e562212 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507 F src/util.c 10d910e04a4f3842042485e0df01a484f57f912c10b60b3a09ccddd5019bd138 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 27ab41c9102e7801ff829488fc123a8040da008bef373d6704efbe2f93e1da90 -R 72df5515bebd9dc031bf51cf11383344 +P fb9c9bb284d441bd7aa34c87b6fd8ce57d036c17623d82354154fc6286bdd134 +R 3288eb40d3c7dad01a2cfbfeeeb4e1e7 U drh -Z dca30fedc0b8883c88ac3723c3316cd7 +Z dcf9ae594cbfb14d7391aa7ed9f45058 diff --git a/manifest.uuid b/manifest.uuid index 7c08b6a36c..2f83dfbcb3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fb9c9bb284d441bd7aa34c87b6fd8ce57d036c17623d82354154fc6286bdd134 \ No newline at end of file +932a37275d7e932f8237d32c8fc6087ed8cd342fe01ef2f7a43c7237ab84c9ac \ No newline at end of file diff --git a/src/build.c b/src/build.c index 48f3a1c1ea..c688a68e0f 100644 --- a/src/build.c +++ b/src/build.c @@ -901,8 +901,6 @@ i16 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){ ** and only there are VIRTUAL columns to the left. ** ** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro. -** -** This function is the inverse of sqlite3TableColumnToStorage(). */ i16 sqlite3StorageColumnToTable(Table *pTab, i16 iCol){ if( pTab->tabFlags & TF_HasVirtual ){ @@ -919,12 +917,36 @@ i16 sqlite3StorageColumnToTable(Table *pTab, i16 iCol){ /* Convert a table column number into a storage column number. ** ** The storage column number (0,1,2,....) is the index of the value -** as it appears in the record on disk. The true column number -** is the index (0,1,2,...) of the column in the CREATE TABLE statement. +** as it appears in the record on disk. Or, if the input column is +** the N-th virtual column (zero-based) then the storage number is +** the number of non-virtual columns in the table plus N. ** -** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro. +** The true column number is the index (0,1,2,...) of the column in +** the CREATE TABLE statement. ** -** This function is the inverse of sqlite3StorageColumnToTable(). +** If the input column is a VIRTUAL column, then it should not appear +** in storage. But the value sometimes is cached in registers that +** follow the range of registers used to construct storage. This +** avoids computing the same VIRTUAL column multiple times, and provides +** values for use by OP_Param opcodes in triggers. Hence, if the +** input column is a VIRTUAL table, put it after all the other columns. +** +** In the following, N means "normal column", S means STORED, and +** V means VIRTUAL. Suppose the CREATE TABLE has columns like this: +** +** CREATE TABLE ex(N,S,V,N,S,V,N,S,V); +** -- 0 1 2 3 4 5 6 7 8 +** +** Then the mapping from this function is as follows: +** +** INPUTS: 0 1 2 3 4 5 6 7 8 +** OUTPUTS: 0 1 6 2 3 7 4 5 8 +** +** So, in other words, this routine shifts all the virtual columns to +** the end. +** +** If SQLITE_OMIT_GENERATED_COLUMNS then there are no virtual columns and +** this routine is a no-op macro. */ i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){ int i; @@ -934,7 +956,13 @@ i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){ for(i=0, n=0; iaCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) n++; } - return n; + if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ + /* iCol is a virtual column itself */ + return pTab->nNVCol + i - n; + }else{ + /* iCol is a normal or stored column */ + return n; + } } #endif diff --git a/src/expr.c b/src/expr.c index 01e99428f3..b868ed969a 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3604,16 +3604,11 @@ expr_code_doover: return 0; } pCol->colFlags |= COLFLAG_BUSY; - if( pCol->colFlags & COLFLAG_VIRTUAL ){ - target = sqlite3ExprCodeTarget(pParse, pCol->pDflt, target); - }else{ - target = iSrc; - if( pCol->colFlags & COLFLAG_NOTAVAIL ){ - sqlite3ExprCode(pParse, pCol->pDflt, iSrc); - } + if( pCol->colFlags & COLFLAG_NOTAVAIL ){ + sqlite3ExprCode(pParse, pCol->pDflt, iSrc); } pCol->colFlags &= ~(COLFLAG_BUSY|COLFLAG_NOTAVAIL); - return target; + return iSrc; }else #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ if( pCol->affinity==SQLITE_AFF_REAL ){ @@ -4088,17 +4083,19 @@ expr_code_doover: ** p1==2 -> old.b p1==5 -> new.b */ Table *pTab = pExpr->y.pTab; - int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn; + int iCol = pExpr->iColumn; + int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + + (iCol>=0 ? sqlite3TableColumnToStorage(pTab, iCol) : -1); assert( pExpr->iTable==0 || pExpr->iTable==1 ); - assert( pExpr->iColumn>=-1 && pExpr->iColumnnCol ); - assert( pTab->iPKey<0 || pExpr->iColumn!=pTab->iPKey ); + assert( iCol>=-1 && iColnCol ); + assert( pTab->iPKey<0 || iCol!=pTab->iPKey ); assert( p1>=0 && p1<(pTab->nCol*2+2) ); sqlite3VdbeAddOp2(v, OP_Param, p1, target); VdbeComment((v, "r[%d]=%s.%s", target, (pExpr->iTable ? "new" : "old"), - (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[pExpr->iColumn].zName) + (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[iCol].zName) )); #ifndef SQLITE_OMIT_FLOATING_POINT @@ -4107,9 +4104,7 @@ expr_code_doover: ** ** EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to ** floating point when extracting it from the record. */ - if( pExpr->iColumn>=0 - && pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL - ){ + if( iCol>=0 && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, target); } #endif diff --git a/src/insert.c b/src/insert.c index e15e9feed2..7eba08e955 100644 --- a/src/insert.c +++ b/src/insert.c @@ -205,22 +205,23 @@ static int readsTable(Parse *p, int iDb, Table *pTab){ /* ** All regular columns for table pTab have been puts into registers ** starting with iRegStore. The registers that correspond to STORED -** columns have not been initialized. This routine goes back and computes -** the values for STORED columns based on the previously computed normal -** columns. +** or VIRTUAL columns have not yet been initialized. This routine goes +** back and computes the values for those columns based on the previously +** computed normal columns. */ -void sqlite3ComputeStoredColumns( +void sqlite3ComputeGeneratedColumns( Parse *pParse, /* Parsing context */ int iRegStore, /* Register holding the first column */ Table *pTab /* The table */ ){ int i; - /* Because there can be multiple STORED columns that refer to one another, - ** either directly or through VIRTUAL columns, this is a two pass - ** algorithm. On the first pass, mark all STORED columns as NOT-AVAILABLE. + int nv; + /* Because there can be multiple generated columns that refer to one another, + ** this is a two-pass algorithm. On the first pass, mark all generated + ** columns as "not available". */ for(i=0; inCol; i++){ - if( pTab->aCol[i].colFlags & COLFLAG_STORED ){ + if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ pTab->aCol[i].colFlags |= COLFLAG_NOTAVAIL; } } @@ -230,16 +231,23 @@ void sqlite3ComputeStoredColumns( ** they are needed. */ pParse->iSelfTab = -iRegStore; - for(i=0; inCol; i++, iRegStore++){ + for(i=nv=0; inCol; i++){ u32 colFlags = pTab->aCol[i].colFlags; - if( (colFlags & COLFLAG_VIRTUAL)!=0 ){ - /* Virtual columns are not stored */ - iRegStore--; - }else if( (colFlags & COLFLAG_NOTAVAIL)!=0 ){ - /* Stored columns are handled on the second pass */ - sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore); + if( (colFlags & COLFLAG_NOTAVAIL)!=0 ){ + assert( colFlags & COLFLAG_GENERATED ); + if( colFlags & COLFLAG_VIRTUAL ){ + /* Virtual columns go at the end */ + assert( pTab->nNVCol+nv == sqlite3TableColumnToStorage(pTab,i) ); + sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, + iRegStore+pTab->nNVCol+nv); + }else{ + /* Stored columns go in column order */ + assert( i-nv == sqlite3TableColumnToStorage(pTab,i) ); + sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore+i-nv); + } colFlags &= ~COLFLAG_NOTAVAIL; } + if( (colFlags & COLFLAG_VIRTUAL)!=0 ) nv++; } pParse->iSelfTab = 0; } @@ -1055,7 +1063,6 @@ void sqlite3Insert( int k; u32 colFlags; assert( i>=nHidden ); - assert( iRegStore==sqlite3TableColumnToStorage(pTab,i)+regRowid+1 ); if( i==pTab->iPKey ){ /* The value of the INTEGER PRIMARY KEY column is always a NULL. ** Whenever this column is read, the rowid will be substituted @@ -1108,10 +1115,10 @@ void sqlite3Insert( } #ifndef SQLITE_OMIT_GENERATED_COLUMNS - /* Compute the new value for STORED columns after all other + /* Compute the new value for generated columns after all other ** columns have already been computed */ - if( pTab->tabFlags & TF_HasStored ){ - sqlite3ComputeStoredColumns(pParse, regRowid+1, pTab); + if( pTab->tabFlags & (TF_HasStored|TF_HasVirtual) ){ + sqlite3ComputeGeneratedColumns(pParse, regRowid+1, pTab); } #endif @@ -1454,19 +1461,11 @@ void sqlite3GenerateConstraintChecks( assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); addr1 = 0; - if( (pTab->tabFlags & TF_HasVirtual)==0 ){ - iReg = regNewData+1+i; - }else if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){ - iReg = ++pParse->nMem; - assert( pParse->iSelfTab==0 ); - pParse->iSelfTab = -regNewData; - sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iReg); - pParse->iSelfTab = 0; - if( onError==OE_Replace ) onError = OE_Abort; - }else{ - testcase( i!=sqlite3TableColumnToStorage(pTab, i) ); - iReg = sqlite3TableColumnToStorage(pTab, i) + regNewData + 1; - } + testcase( i!=sqlite3TableColumnToStorage(pTab, i) ); + testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ); + testcase( pTab->aCol[i].colFlags & COLFLAG_STORED ); + testcase( pTab->aCol[i].colFlags & COLFLAG_GENERATED ); + iReg = sqlite3TableColumnToStorage(pTab, i) + regNewData + 1; switch( onError ){ case OE_Replace: { assert( onError==OE_Replace ); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 10b2eeaf3f..00013bd172 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4044,7 +4044,7 @@ void sqlite3FreeIndex(sqlite3*, Index*); #endif void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*); #ifndef SQLITE_OMIT_GENERATED_COLUMNS - void sqlite3ComputeStoredColumns(Parse*, int, Table*); + void sqlite3ComputeGeneratedColumns(Parse*, int, Table*); #endif void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*); IdList *sqlite3IdListAppend(Parse*, IdList*, Token*); diff --git a/src/update.c b/src/update.c index 08502cf5e3..79b6fbd2a5 100644 --- a/src/update.c +++ b/src/update.c @@ -693,8 +693,8 @@ void sqlite3Update( } } #ifndef SQLITE_OMIT_GENERATED_COLUMNS - if( pTab->tabFlags & TF_HasStored ){ - sqlite3ComputeStoredColumns(pParse, regNew, pTab); + if( pTab->tabFlags & (TF_HasStored|TF_HasVirtual) ){ + sqlite3ComputeGeneratedColumns(pParse, regNew, pTab); } #endif @@ -737,8 +737,8 @@ void sqlite3Update( } } #ifndef SQLITE_OMIT_GENERATED_COLUMNS - if( pTab->tabFlags & TF_HasStored ){ - sqlite3ComputeStoredColumns(pParse, regNew, pTab); + if( pTab->tabFlags & (TF_HasStored|TF_HasVirtual) ){ + sqlite3ComputeGeneratedColumns(pParse, regNew, pTab); } #endif } From f5f1915d599b1a0aba8fab35178c90031fdb362d Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 21 Oct 2019 01:04:11 +0000 Subject: [PATCH 21/31] Changes to the INSERT logic to make it simpler and faster and so that it works with generated columns and BEFORE triggers. FossilOrigin-Name: bc368cb090376d33d3844e3689c4f6bd19eed758e39b878ee67fef93b1c839ea --- manifest | 18 ++--- manifest.uuid | 2 +- src/build.c | 4 +- src/expr.c | 36 +-------- src/insert.c | 196 +++++++++++++++++++++++++++--------------------- src/sqliteInt.h | 1 - 6 files changed, 125 insertions(+), 132 deletions(-) diff --git a/manifest b/manifest index 2d2a9b70e5..b164bf9dd0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Work\stoward\sgetting\sgenerated\scolumns\sto\swork\swith\striggers.\s\sStill\smore\nwork\sto\sdo\sin\sthis\sarea. -D 2019-10-19T18:47:27.679 +C Changes\sto\sthe\sINSERT\slogic\sto\smake\sit\ssimpler\sand\sfaster\sand\sso\sthat\nit\sworks\swith\sgenerated\scolumns\sand\sBEFORE\striggers. +D 2019-10-21T01:04:11.302 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c c6421066f1ce6ce789a8346818f7ce00fec47f469004fa6b6d31643d793d2b2d +F src/build.c b5eefc5b29788ff43062aa15f08e17df843fcc3dedbf6ad2e8a5ecfdd71c83a8 F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -477,7 +477,7 @@ F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319 F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf -F src/expr.c ffa1cda4277078c0572055f46f83d06dc2e0a89b843e601bef6f9dc8fd430f41 +F src/expr.c e00d483f68fcaa2bfb334ba21550f949ca92b239f86ca22824577988efc53010 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 6271fda51794b569d736eba4097d28f13080cd0c9eb66d5fcecb4b77336fae50 F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c fd8ba5c85b6e96770957f3f23b66fb619adb287dcd53e6f19fb5e8ddaf9b792a +F src/insert.c db411a28a6c5bf159c0ea9f9b7dde1b41b4be6f393a77b574e8086dd4bea0153 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -530,7 +530,7 @@ F src/shell.c.in 3093bdf5eedd91da08f0268f1442aa510a60798c9441868149ddbecdf8bcaa7 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h 1929d5f85ce9e4aba60540c70f88ef6fcd2bb272ee52b7dfee96126775dd12b9 +F src/sqliteInt.h 49ade8ae4322263c4bfb46ededd566f6351a82380294bb11efb91d2ae100ca24 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P fb9c9bb284d441bd7aa34c87b6fd8ce57d036c17623d82354154fc6286bdd134 -R 3288eb40d3c7dad01a2cfbfeeeb4e1e7 +P 932a37275d7e932f8237d32c8fc6087ed8cd342fe01ef2f7a43c7237ab84c9ac +R 47a4a5169a9bdb2c3c1d9653909f73fd U drh -Z dcf9ae594cbfb14d7391aa7ed9f45058 +Z f477eaf49473bce8390a1ef42b7a8a95 diff --git a/manifest.uuid b/manifest.uuid index 2f83dfbcb3..1071898fde 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -932a37275d7e932f8237d32c8fc6087ed8cd342fe01ef2f7a43c7237ab84c9ac \ No newline at end of file +bc368cb090376d33d3844e3689c4f6bd19eed758e39b878ee67fef93b1c839ea \ No newline at end of file diff --git a/src/build.c b/src/build.c index c688a68e0f..4501d41d46 100644 --- a/src/build.c +++ b/src/build.c @@ -2329,7 +2329,7 @@ void sqlite3EndTable( pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect, SQLITE_AFF_BLOB); if( pSelTab==0 ) return; assert( p->aCol==0 ); - p->nCol = pSelTab->nCol; + p->nCol = p->nNVCol = pSelTab->nCol; p->aCol = pSelTab->aCol; pSelTab->nCol = 0; pSelTab->aCol = 0; @@ -2617,7 +2617,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ ** the column names from the SELECT statement that defines the view. */ assert( pTable->aCol==0 ); - pTable->nCol = pSelTab->nCol; + pTable->nCol = pTable->nNVCol = pSelTab->nCol; pTable->aCol = pSelTab->aCol; pSelTab->nCol = 0; pSelTab->aCol = 0; diff --git a/src/expr.c b/src/expr.c index b868ed969a..1c562fdf5e 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4337,14 +4337,10 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ int inReg; assert( target>0 && target<=pParse->nMem ); - if( pExpr && pExpr->op==TK_REGISTER ){ - sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target); - }else{ - inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); - assert( pParse->pVdbe!=0 || pParse->db->mallocFailed ); - if( inReg!=target && pParse->pVdbe ){ - sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target); - } + inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); + assert( pParse->pVdbe!=0 || pParse->db->mallocFailed ); + if( inReg!=target && pParse->pVdbe ){ + sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target); } } @@ -4374,30 +4370,6 @@ void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ } } -/* -** Generate code that evaluates the given expression and puts the result -** in register target. -** -** Also make a copy of the expression results into another "cache" register -** and modify the expression so that the next time it is evaluated, -** the result is a copy of the cache register. -** -** This routine is used for expressions that are used multiple -** times. They are evaluated once and the results of the expression -** are reused. -*/ -void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ - Vdbe *v = pParse->pVdbe; - int iMem; - - assert( target>0 ); - assert( pExpr->op!=TK_REGISTER ); - sqlite3ExprCode(pParse, pExpr, target); - iMem = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Copy, target, iMem); - exprToRegister(pExpr, iMem); -} - /* ** Generate code that pushes the value of every element of the given ** expression list into a sequence of registers beginning at target. diff --git a/src/insert.c b/src/insert.c index 7eba08e955..8640a77b66 100644 --- a/src/insert.c +++ b/src/insert.c @@ -561,7 +561,7 @@ void sqlite3Insert( Parse *pParse, /* Parser context */ SrcList *pTabList, /* Name of table into which we are inserting */ Select *pSelect, /* A SELECT statement to use as the data source */ - IdList *pColumn, /* Column names corresponding to IDLIST. */ + IdList *pColumn, /* Column names corresponding to IDLIST, or NULL. */ int onError, /* How to handle constraint errors */ Upsert *pUpsert /* ON CONFLICT clauses for upsert, or NULL */ ){ @@ -694,8 +694,8 @@ void sqlite3Insert( */ regAutoinc = autoIncBegin(pParse, iDb, pTab); - /* Allocate registers for holding the rowid of the new row, - ** the content of the new row, and the assembled row record. + /* Allocate a block registers to hold the rowid and the values + ** for all columns of the new row. */ regRowid = regIns = pParse->nMem+1; pParse->nMem += pTab->nCol + 1; @@ -714,7 +714,15 @@ void sqlite3Insert( ** the index into IDLIST of the primary key column. ipkColumn is ** the index of the primary key as it appears in IDLIST, not as ** is appears in the original table. (The index of the INTEGER - ** PRIMARY KEY in the original table is pTab->iPKey.) + ** PRIMARY KEY in the original table is pTab->iPKey.) After this + ** loop, if ipkColumn==(-1), that means that integer primary key + ** is unspecified, and hence the table is either WITHOUT ROWID or + ** it will automatically generated an integer primary key. + ** + ** bIdListInOrder is true if the columns in IDLIST are in storage + ** order. This enables an optimization that avoids shuffling the + ** columns into storage order. False negatives are harmless, + ** but false positives will cause database corruption. */ bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0; if( pColumn ){ @@ -937,8 +945,88 @@ void sqlite3Insert( */ addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm); VdbeCoverage(v); + if( ipkColumn>=0 ){ + /* tag-20191021-001: If the INTEGER PRIMARY KEY is being generated by the + ** SELECT, go ahead and copy the value into the rowid slot now, so that + ** the value does not get overwritten by a NULL at tag-20191021-002. */ + sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid); + } } + /* Compute data for ordinary columns of the new entry. Values + ** are written in storage order into registers starting with regData. + ** Only ordinary columns are computed in this loop. The rowid + ** (if there is one) is computed later and generated columns are + ** computed after the rowid since they might depend on the value + ** of the rowid. + */ + nHidden = 0; + iRegStore = regData; assert( regData==regRowid+1 ); + for(i=0; inCol; i++, iRegStore++){ + int k; + u32 colFlags; + assert( i>=nHidden ); + if( i==pTab->iPKey ){ + /* tag-20191021-002: References to the INTEGER PRIMARY KEY are filled + ** using the rowid. So put a NULL in the IPK slot of the record to avoid + ** using excess space. The file format definition requires this extra + ** NULL - we cannot optimize further by skipping the column completely */ + sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); + continue; + } + if( ((colFlags = pTab->aCol[i].colFlags) & COLFLAG_NOINSERT)!=0 ){ + nHidden++; + if( (colFlags & COLFLAG_VIRTUAL)!=0 ){ + /* Virtual columns do not participate in OP_MakeRecord. So back up + ** iRegStore by one slot to compensate for the iRegStore++ in the + ** outer for() loop */ + iRegStore--; + continue; + }else if( (colFlags & COLFLAG_STORED)!=0 ){ + /* Stored columns are computed later. But if there are BEFORE + ** triggers, the slots used for stored columns will be OP_Copy-ed + ** to a second block of registers, so the register needs to be + ** initialized to NULL to avoid an uninitialized register read */ + if( tmask & TRIGGER_BEFORE ){ + sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); + } + continue; + }else if( pColumn==0 ){ + /* Hidden columns that are not explicitly named in the INSERT + ** get there default value */ + sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); + continue; + } + } + if( pColumn ){ + for(j=0; jnId && pColumn->a[j].idx!=i; j++){} + if( j>=pColumn->nId ){ + /* A column not named in the insert column list gets its + ** default value */ + sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); + continue; + } + k = j; + }else if( nColumn==0 ){ + /* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */ + sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); + continue; + }else{ + k = i - nHidden; + } + + if( useTempTable ){ + sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore); + }else if( pSelect ){ + if( regFromSelect!=regData ){ + sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore); + } + }else{ + sqlite3ExprCode(pParse, pList->a[k].pExpr, iRegStore); + } + } + + /* Run the BEFORE and INSTEAD OF triggers, if there are any */ endOfLoop = sqlite3VdbeMakeLabel(pParse); @@ -973,25 +1061,19 @@ void sqlite3Insert( */ assert( !IsVirtual(pTab) ); - /* Create the new column data - */ - for(i=j=0; inCol; i++){ - if( pColumn ){ - for(j=0; jnId; j++){ - if( pColumn->a[j].idx==i ) break; - } - } - if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) - || (pColumn==0 && IsOrdinaryHiddenColumn(&pTab->aCol[i])) ){ - sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1); - }else if( useTempTable ){ - sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1); - }else{ - assert( pSelect==0 ); /* Otherwise useTempTable is true */ - sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1); - } - if( pColumn==0 && !IsOrdinaryHiddenColumn(&pTab->aCol[i]) ) j++; + /* Copy the new data already generated. */ + assert( pTab->nNVCol>0 ); + sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1); + +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + /* Compute the new value for generated columns after all other + ** columns have already been computed. This must be done after + ** computing the ROWID in case one of the generated columns + ** refers to the ROWID. */ + if( pTab->tabFlags & (TF_HasStored|TF_HasVirtual) ){ + sqlite3ComputeGeneratedColumns(pParse, regCols+1, pTab); } +#endif /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger, ** do not attempt any conversions before assembling the record. @@ -1009,19 +1091,17 @@ void sqlite3Insert( sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1); } - /* Compute the content of the next row to insert into a range of - ** registers beginning at regIns. - */ if( !isView ){ if( IsVirtual(pTab) ){ /* The row that the VUpdate opcode will delete: none */ sqlite3VdbeAddOp2(v, OP_Null, 0, regIns); } if( ipkColumn>=0 ){ + /* Compute the new rowid */ if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regRowid); }else if( pSelect ){ - sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid); + /* Rowid already initialized at tag-20191021-001 */ }else{ Expr *pIpk = pList->a[ipkColumn].pExpr; if( pIpk->op==TK_NULL && !IsVirtual(pTab) ){ @@ -1054,69 +1134,11 @@ void sqlite3Insert( } autoIncStep(pParse, regAutoinc, regRowid); - /* Compute data for all columns of the new entry, beginning - ** with the first column. - */ - nHidden = 0; - iRegStore = regRowid+1; - for(i=0; inCol; i++, iRegStore++){ - int k; - u32 colFlags; - assert( i>=nHidden ); - if( i==pTab->iPKey ){ - /* The value of the INTEGER PRIMARY KEY column is always a NULL. - ** Whenever this column is read, the rowid will be substituted - ** in its place. Hence, fill this column with a NULL to avoid - ** taking up data space with information that will never be used. - ** As there may be shallow copies of this value, make it a soft-NULL */ - sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); - continue; - } - if( ((colFlags = pTab->aCol[i].colFlags) & COLFLAG_NOINSERT)!=0 ){ - nHidden++; - if( (colFlags & COLFLAG_VIRTUAL)!=0 ){ - /* Virtual columns are no stored */ - iRegStore--; - continue; - }else if( (colFlags & COLFLAG_STORED)!=0 ){ - /* Stored columns are handled on the second pass */ - continue; - }else if( pColumn==0 ){ - /* Hidden columns that are not explicitly named in the INSERT */ - sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); - continue; - } - } - if( pColumn ){ - for(j=0; jnId && pColumn->a[j].idx!=i; j++){} - if( j>=pColumn->nId ){ - /* A column not named in the insert column list gets its - ** default value */ - sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); - continue; - } - k = j; - }else if( nColumn==0 ){ - sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); - continue; - }else{ - k = i - nHidden; - } - - if( useTempTable ){ - sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore); - }else if( pSelect ){ - if( regFromSelect!=regData ){ - sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore); - } - }else{ - sqlite3ExprCode(pParse, pList->a[k].pExpr, iRegStore); - } - } - #ifndef SQLITE_OMIT_GENERATED_COLUMNS /* Compute the new value for generated columns after all other - ** columns have already been computed */ + ** columns have already been computed. This must be done after + ** computing the ROWID in case one of the generated columns + ** refers to the ROWID. */ if( pTab->tabFlags & (TF_HasStored|TF_HasVirtual) ){ sqlite3ComputeGeneratedColumns(pParse, regRowid+1, pTab); } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 00013bd172..e586674f91 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4100,7 +4100,6 @@ void sqlite3ExprCodeFactorable(Parse*, Expr*, int); int sqlite3ExprCodeAtInit(Parse*, Expr*, int); int sqlite3ExprCodeTemp(Parse*, Expr*, int*); int sqlite3ExprCodeTarget(Parse*, Expr*, int); -void sqlite3ExprCodeAndCache(Parse*, Expr*, int); int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8); #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ From 427b96aedf422b1a8e906e47e8852033c70939c4 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 22 Oct 2019 13:01:24 +0000 Subject: [PATCH 22/31] New testcase() macros. Fix a problem with INSERT when the IPK is to the right of generated columns. FossilOrigin-Name: 412799fc5527aaca987e4e04b8a4f774dcdb70fb80e3a126dc3a26d48a66935c --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/build.c | 8 ++++++-- src/insert.c | 28 ++++++++++++++++++++++++---- src/sqliteInt.h | 1 + src/update.c | 12 +++++++++--- 6 files changed, 50 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index ca085798dd..939aaa0a07 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\schanges\son\strunk\sinto\sthe\sgenerated-columns\sbranch. -D 2019-10-22T12:02:09.134 +C New\stestcase()\smacros.\s\sFix\sa\sproblem\swith\sINSERT\swhen\sthe\sIPK\sis\sto\sthe\nright\sof\sgenerated\scolumns. +D 2019-10-22T13:01:24.252 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c c8d76afe573ad68678206f85c122544d65932f95ad067e17570de930de4b0276 +F src/build.c acf54f35164aff7f0b06b82aae357e76e08b74e4c904bafd96643d4e155f34f8 F src/callback.c 88615dfc0a82167b65b452b4b305dbf86be77200b3343c6ffc6d03e92a01d181 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c f657ee9898f147d3dd96986dae2611afb75bcef8dd3644f182232f5ca2268a0e +F src/insert.c 760925fe9b4796e968bb9cd11426a3b9f6cc2c35b7b7acc5f25bcc84b73fb5a8 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -530,7 +530,7 @@ F src/shell.c.in 3093bdf5eedd91da08f0268f1442aa510a60798c9441868149ddbecdf8bcaa7 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h 3a498ce50d079e0b2c4d780fc48d93024afaac4511021bc121d4277cb1a3df56 +F src/sqliteInt.h ca968d2d348b7aa4cef7a16fdb7738c15834318e5bd9eca8a49388f48f0695a8 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -592,7 +592,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c 7b17f6e2f20f6cbcb0b215025a86b7457c38451fc7622f705e553d7a488c572d F src/treeview.c fddeb413159c3eeeaea3f496172f121cf3695606c461dc4e6dcee51417952df5 F src/trigger.c 845ccc08f60716c58aa28fe6470385c18ef8c4e1d88c93dcf449bc13d464eb2e -F src/update.c e5c432097191e6e6c73e48364daa58b257b30a8b0d54b018fd0bd9415cd7b553 +F src/update.c 287146d2ce191228f0afaa34ffcaaaa196e2c2e2664008914e925dea6a64403e F src/upsert.c b445315c8958d8f17ec3297d06842e61dacaad0633ccaec1e4e160de7e562212 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507 F src/util.c 10d910e04a4f3842042485e0df01a484f57f912c10b60b3a09ccddd5019bd138 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P bc368cb090376d33d3844e3689c4f6bd19eed758e39b878ee67fef93b1c839ea c7da1c01f1f239e68c2173ac5748b8c5798271e43bdcee68f51f97cd0ca92bd5 -R 3ed2fbe0c143869ff55bbbadcc27c112 +P ba123b8c201053d8f9387de38f3513b06f7721b28d79fab8489f96d336105117 +R c1cc6d4a971f76b9e92c16fa65923060 U drh -Z c16a467e1be0aad7834a9c102a3d7298 +Z 35d27d665bc3fbce0f6de471df281b5a diff --git a/manifest.uuid b/manifest.uuid index 7095e594e6..0a61aea937 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ba123b8c201053d8f9387de38f3513b06f7721b28d79fab8489f96d336105117 \ No newline at end of file +412799fc5527aaca987e4e04b8a4f774dcdb70fb80e3a126dc3a26d48a66935c \ No newline at end of file diff --git a/src/build.c b/src/build.c index ad65c25ef7..2ba9398226 100644 --- a/src/build.c +++ b/src/build.c @@ -2207,11 +2207,15 @@ void sqlite3EndTable( } #endif /* !defined(SQLITE_OMIT_CHECK) */ #ifndef SQLITE_OMIT_GENERATED_COLUMNS - if( p->tabFlags & (TF_HasVirtual|TF_HasStored) ){ + if( p->tabFlags & TF_HasGenerated ){ int ii; + testcase( p->tabFlags & TF_HasVirtual ); + testcase( p->tabFlags & TF_HasStored ); for(ii=0; iinCol; ii++){ u32 colFlags = p->aCol[ii].colFlags; - if( (colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL))!=0 ){ + if( (colFlags & COLFLAG_GENERATED)!=0 ){ + testcase( colFlags & COLFLAG_VIRTUAL ); + testcase( colFlags & COLFLAG_STORED ); sqlite3ResolveSelfReference(pParse, p, NC_GenCol, p->aCol[ii].pDflt, 0); } diff --git a/src/insert.c b/src/insert.c index c90f9d2726..1995f9634c 100644 --- a/src/insert.c +++ b/src/insert.c @@ -222,6 +222,8 @@ void sqlite3ComputeGeneratedColumns( */ for(i=0; inCol; i++){ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ + testcase( pTab->aCol[i].colflags & COLFLAG_VIRTUAL ); + testcase( pTab->aCol[i].colflags & COLFLAG_STORED ); pTab->aCol[i].colFlags |= COLFLAG_NOTAVAIL; } } @@ -854,6 +856,19 @@ void sqlite3Insert( */ if( pColumn==0 && nColumn>0 ){ ipkColumn = pTab->iPKey; +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( pTab->tabFlags & TF_HasGenerated ){ + testcase( pTab->tabFlags & TF_HasVirtual ); + testcase( pTab->tabFlags & TF_HasGenerated ); + for(i=ipkColumn-1; i>=0; i--){ + if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ + testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ); + testcase( pTab->aCol[i].colFlags & COLFLAG_GENERATED ); + ipkColumn--; + } + } + } +#endif } /* Make sure the number of columns in the source data matches the number @@ -1070,7 +1085,9 @@ void sqlite3Insert( ** columns have already been computed. This must be done after ** computing the ROWID in case one of the generated columns ** refers to the ROWID. */ - if( pTab->tabFlags & (TF_HasStored|TF_HasVirtual) ){ + if( pTab->tabFlags & TF_HasGenerated ){ + testcase( pTab->tabFlags & TF_HasVirtual ); + testcase( pTab->tabFlags & TF_HasStored ); sqlite3ComputeGeneratedColumns(pParse, regCols+1, pTab); } #endif @@ -1139,7 +1156,9 @@ void sqlite3Insert( ** columns have already been computed. This must be done after ** computing the ROWID in case one of the generated columns ** refers to the ROWID. */ - if( pTab->tabFlags & (TF_HasStored|TF_HasVirtual) ){ + if( pTab->tabFlags & TF_HasGenerated ){ + testcase( pTab->tabFlags & TF_HasVirtual ); + testcase( pTab->tabFlags & TF_HasStored ); sqlite3ComputeGeneratedColumns(pParse, regRowid+1, pTab); } #endif @@ -1486,7 +1505,6 @@ void sqlite3GenerateConstraintChecks( testcase( i!=sqlite3TableColumnToStorage(pTab, i) ); testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ); testcase( pTab->aCol[i].colFlags & COLFLAG_STORED ); - testcase( pTab->aCol[i].colFlags & COLFLAG_GENERATED ); iReg = sqlite3TableColumnToStorage(pTab, i) + regNewData + 1; switch( onError ){ case OE_Replace: { @@ -2422,7 +2440,9 @@ static int xferOptimization( /* Generator expressions for generated columns must match */ if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){ if( sqlite3ExprCompare(0, pSrcCol->pDflt, pDestCol->pDflt, -1)!=0 ){ - return 0; /* Different generator expressions */ + testcase( pDestCol->colflags & COLFLAG_VIRTUAL ); + testcase( pDestCol->colflags & COLFLAG_STORED ); + return 0; /* Different generator expressions */ } } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c9dee9e23f..06464acb55 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2037,6 +2037,7 @@ struct Table { #define TF_HasStat1 0x0010 /* nRowLogEst set from sqlite_stat1 */ #define TF_HasVirtual 0x0020 /* Has one or more VIRTUAL columns */ #define TF_HasStored 0x0040 /* Has one or more STORED columns */ +#define TF_HasGenerated 0x0060 /* Combo: HasVirtual + HasStored */ #define TF_WithoutRowid 0x0080 /* No rowid. PRIMARY KEY is the key */ #define TF_StatsUsed 0x0100 /* Query planner decisions affected by ** Index.aiRowLogEst[] values */ diff --git a/src/update.c b/src/update.c index 79b6fbd2a5..48413a0df9 100644 --- a/src/update.c +++ b/src/update.c @@ -313,7 +313,9 @@ void sqlite3Update( chngPk = 1; } #ifndef SQLITE_OMIT_GENERATED_COLUMNS - else if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){ + else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){ + testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ); + testcase( pTab->aCol[i].colFlags & COLFLAG_STORED ); sqlite3ErrorMsg(pParse, "cannot UPDATE generated column \"%s\"", pTab->aCol[j].zName); @@ -693,7 +695,9 @@ void sqlite3Update( } } #ifndef SQLITE_OMIT_GENERATED_COLUMNS - if( pTab->tabFlags & (TF_HasStored|TF_HasVirtual) ){ + if( pTab->tabFlags & TF_HasGenerated ){ + testcase( pTab->tabFlags & TF_HasVirtual ); + testcase( pTab->tabFlags & TF_HasStored ); sqlite3ComputeGeneratedColumns(pParse, regNew, pTab); } #endif @@ -737,7 +741,9 @@ void sqlite3Update( } } #ifndef SQLITE_OMIT_GENERATED_COLUMNS - if( pTab->tabFlags & (TF_HasStored|TF_HasVirtual) ){ + if( pTab->tabFlags & TF_HasGenerated ){ + testcase( pTab->tabFlags & TF_HasVirtual ); + testcase( pTab->tabFlags & TF_HasStored ); sqlite3ComputeGeneratedColumns(pParse, regNew, pTab); } #endif From 7e7fd73b25f83b6aac246a79990e0f5ff3019e7c Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 22 Oct 2019 13:59:23 +0000 Subject: [PATCH 23/31] In UPDATE processing, include generated columns in the set of columns being updated if and only if their generator expressions reference some other column that is being updated. FossilOrigin-Name: d38176e93a628e03f1bd8b689fbc4152a1495388da917c2d89cefed04353d2d6 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/build.c | 10 ++++++++-- src/update.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 939aaa0a07..723757465a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\stestcase()\smacros.\s\sFix\sa\sproblem\swith\sINSERT\swhen\sthe\sIPK\sis\sto\sthe\nright\sof\sgenerated\scolumns. -D 2019-10-22T13:01:24.252 +C In\sUPDATE\sprocessing,\sinclude\sgenerated\scolumns\sin\sthe\sset\sof\scolumns\sbeing\nupdated\sif\sand\sonly\sif\stheir\sgenerator\sexpressions\sreference\ssome\sother\ncolumn\sthat\sis\sbeing\supdated. +D 2019-10-22T13:59:23.530 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c acf54f35164aff7f0b06b82aae357e76e08b74e4c904bafd96643d4e155f34f8 +F src/build.c 27471914e516d7d0f21d16c74f9e84bdfda1160bfd11e33a74cbe1d5a08dbc9e F src/callback.c 88615dfc0a82167b65b452b4b305dbf86be77200b3343c6ffc6d03e92a01d181 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -592,7 +592,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c 7b17f6e2f20f6cbcb0b215025a86b7457c38451fc7622f705e553d7a488c572d F src/treeview.c fddeb413159c3eeeaea3f496172f121cf3695606c461dc4e6dcee51417952df5 F src/trigger.c 845ccc08f60716c58aa28fe6470385c18ef8c4e1d88c93dcf449bc13d464eb2e -F src/update.c 287146d2ce191228f0afaa34ffcaaaa196e2c2e2664008914e925dea6a64403e +F src/update.c 3a5e1fa8e29413ee633f049bf9f0e1eb33a03a53cb55b6ea290120b324fbf46e F src/upsert.c b445315c8958d8f17ec3297d06842e61dacaad0633ccaec1e4e160de7e562212 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507 F src/util.c 10d910e04a4f3842042485e0df01a484f57f912c10b60b3a09ccddd5019bd138 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P ba123b8c201053d8f9387de38f3513b06f7721b28d79fab8489f96d336105117 -R c1cc6d4a971f76b9e92c16fa65923060 +P 412799fc5527aaca987e4e04b8a4f774dcdb70fb80e3a126dc3a26d48a66935c +R d35fda238d05afc96b47f324f26c5dfe U drh -Z 35d27d665bc3fbce0f6de471df281b5a +Z 00de734fe264a9e4a103cd3816a6d374 diff --git a/manifest.uuid b/manifest.uuid index 0a61aea937..e9177c9e9c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -412799fc5527aaca987e4e04b8a4f774dcdb70fb80e3a126dc3a26d48a66935c \ No newline at end of file +d38176e93a628e03f1bd8b689fbc4152a1495388da917c2d89cefed04353d2d6 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 2ba9398226..efdcb59b1e 100644 --- a/src/build.c +++ b/src/build.c @@ -1405,6 +1405,12 @@ void sqlite3AddDefaultValue( if( !sqlite3ExprIsConstantOrFunction(pExpr, db->init.busy) ){ sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", pCol->zName); +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + }else if( pCol->colFlags & COLFLAG_GENERATED ){ + testcase( pCol->colflags & COLFLAG_VIRTUAL ); + testcase( pCol->colflags & COLFLAG_STORED ); + sqlite3ErrorMsg(pParse, "cannot use DEFAULT on a generated column"); +#endif }else{ /* A copy of pExpr is used instead of the original, as pExpr contains ** tokens that point to volatile memory. @@ -1633,14 +1639,14 @@ void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ goto generated_done; generated_error: - sqlite3ErrorMsg(pParse, "incorrect GENERATED ALWAYS AS on column \"%s\"", + sqlite3ErrorMsg(pParse, "error in generated column \"%s\"", pCol->zName); generated_done: sqlite3ExprDelete(pParse->db, pExpr); #else /* Throw and error for the GENERATED ALWAYS AS clause if the ** SQLITE_OMIT_GENERATED_COLUMNS compile-time option is used. */ - sqlite3ErrorMsg(pParse, "GENERATED ALWAYS AS not supported"); + sqlite3ErrorMsg(pParse, "generated columns not supported"); sqlite3ExprDelete(pParse->db, pExpr); #endif } diff --git a/src/update.c b/src/update.c index 48413a0df9..d690b69f95 100644 --- a/src/update.c +++ b/src/update.c @@ -356,6 +356,33 @@ void sqlite3Update( assert( chngPk==0 || chngPk==1 ); chngKey = chngRowid + chngPk; +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + /* Mark generated columns as changing if their generator expressions + ** reference any changing column. The actual aXRef[] value for + ** generated expressions is not used, other than to check to see that it + ** is non-negative, so the value of aXRef[] for generated columns can be + ** set to any non-negative number. We use 99999 so that the value is + ** obvious when looking at aXRef[] in a symbolic debugger. + */ + if( pTab->tabFlags & TF_HasGenerated ){ + int bProgress; + testcase( pTab->tabFlags & TF_HasVirtual ); + testcase( pTab->tabFlags & TF_HasStored ); + do{ + bProgress = 0; + for(i=0; inCol; i++){ + if( aXRef[i]>=0 ) continue; + if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ) continue; + if( sqlite3ExprReferencesUpdatedColumn(pTab->aCol[i].pDflt, + aXRef, chngRowid) ){ + aXRef[i] = 99999; + bProgress = 1; + } + } + }while( bProgress ); + } +#endif + /* The SET expressions are not actually used inside the WHERE loop. ** So reset the colUsed mask. Unless this is a virtual table. In that ** case, set all bits of the colUsed mask (to ensure that the virtual @@ -952,6 +979,7 @@ static void updateVirtualTable( /* Populate the argument registers. */ for(i=0; inCol; i++){ + assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ); if( aXRef[i]>=0 ){ sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); }else{ From f4b1d8dc17dcd01eb01f3cafb3614d37eee31e56 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 22 Oct 2019 15:45:03 +0000 Subject: [PATCH 24/31] Do not allow generated columns in the PRIMARY KEY. FossilOrigin-Name: 1a54743a3d327efc8ecc45b9fde91ddfea3fca36408f9b753453c31f2e4cc69c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/build.c | 19 +++++++++++++++++-- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 723757465a..52be0a76b7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sUPDATE\sprocessing,\sinclude\sgenerated\scolumns\sin\sthe\sset\sof\scolumns\sbeing\nupdated\sif\sand\sonly\sif\stheir\sgenerator\sexpressions\sreference\ssome\sother\ncolumn\sthat\sis\sbeing\supdated. -D 2019-10-22T13:59:23.530 +C Do\snot\sallow\sgenerated\scolumns\sin\sthe\sPRIMARY\sKEY. +D 2019-10-22T15:45:03.587 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c 27471914e516d7d0f21d16c74f9e84bdfda1160bfd11e33a74cbe1d5a08dbc9e +F src/build.c 27c8224737b4649ea6d264e8433e66bc226a6859c8e11a2f9849516c211da4d9 F src/callback.c 88615dfc0a82167b65b452b4b305dbf86be77200b3343c6ffc6d03e92a01d181 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 412799fc5527aaca987e4e04b8a4f774dcdb70fb80e3a126dc3a26d48a66935c -R d35fda238d05afc96b47f324f26c5dfe +P d38176e93a628e03f1bd8b689fbc4152a1495388da917c2d89cefed04353d2d6 +R a71a1c09fd9122c7a52773b96d8fa320 U drh -Z 00de734fe264a9e4a103cd3816a6d374 +Z cf574256bc3dfd7405d0c5f301ba621a diff --git a/manifest.uuid b/manifest.uuid index e9177c9e9c..fcbb946ead 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d38176e93a628e03f1bd8b689fbc4152a1495388da917c2d89cefed04353d2d6 \ No newline at end of file +1a54743a3d327efc8ecc45b9fde91ddfea3fca36408f9b753453c31f2e4cc69c \ No newline at end of file diff --git a/src/build.c b/src/build.c index efdcb59b1e..5cd9473fa2 100644 --- a/src/build.c +++ b/src/build.c @@ -1456,6 +1456,21 @@ static void sqlite3StringToId(Expr *p){ } } +/* +** Tag the given column as being part of the PRIMARY KEY +*/ +static void makeColumnPartOfPrimaryKey(Parse *pParse, Column *pCol){ + pCol->colFlags |= COLFLAG_PRIMKEY; +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + if( pCol->colFlags & COLFLAG_GENERATED ){ + testcase( pCol->colFlags & COLFLAG_VIRTUAL ); + testcase( pCol->colFlags & COLFLAG_STORED ); + sqlite3ErrorMsg(pParse, + "generated columns cannot be part of the PRIMARY KEY"); + } +#endif +} + /* ** Designate the PRIMARY KEY for the table. pList is a list of names ** of columns that form the primary key. If pList is NULL, then the @@ -1495,7 +1510,7 @@ void sqlite3AddPrimaryKey( if( pList==0 ){ iCol = pTab->nCol - 1; pCol = &pTab->aCol[iCol]; - pCol->colFlags |= COLFLAG_PRIMKEY; + makeColumnPartOfPrimaryKey(pParse, pCol); nTerm = 1; }else{ nTerm = pList->nExpr; @@ -1508,7 +1523,7 @@ void sqlite3AddPrimaryKey( for(iCol=0; iColnCol; iCol++){ if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){ pCol = &pTab->aCol[iCol]; - pCol->colFlags |= COLFLAG_PRIMKEY; + makeColumnPartOfPrimaryKey(pParse, pCol); break; } } From e70fa7feba0b07eb1b5fe4f5373182875e709b32 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 22 Oct 2019 21:01:34 +0000 Subject: [PATCH 25/31] Take the declared column time into account when computing the values for generated columns, and apply appropriate affinity. FossilOrigin-Name: 9e04ba22dfce3998e61331ac229ff543ecccc590284c9dd5def21efbe594fba0 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/expr.c | 22 ++++++++++++++++++++-- src/insert.c | 8 ++++---- src/sqliteInt.h | 3 +++ 5 files changed, 36 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index 6999837016..da5bf8a3de 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sthe\srow-value\sfix\sfrom\strunk. -D 2019-10-22T20:16:04.350 +C Take\sthe\sdeclared\scolumn\stime\sinto\saccount\swhen\scomputing\sthe\svalues\sfor\ngenerated\scolumns,\sand\sapply\sappropriate\saffinity. +D 2019-10-22T21:01:34.082 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -477,7 +477,7 @@ F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319 F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf -F src/expr.c 738bcc441279eead08581ee8ee37d0dd56ded11361585b20b0af470c7c785291 +F src/expr.c bf20202a8db15eda35f160df741805509be8c1e5e3258e4770e48db6e27d7994 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 6271fda51794b569d736eba4097d28f13080cd0c9eb66d5fcecb4b77336fae50 F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 760925fe9b4796e968bb9cd11426a3b9f6cc2c35b7b7acc5f25bcc84b73fb5a8 +F src/insert.c 7ab2c74825809a7e3cb1fa5b480d052c96c939dafb449713a7a9da0d949447af F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -530,7 +530,7 @@ F src/shell.c.in 3093bdf5eedd91da08f0268f1442aa510a60798c9441868149ddbecdf8bcaa7 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h ca968d2d348b7aa4cef7a16fdb7738c15834318e5bd9eca8a49388f48f0695a8 +F src/sqliteInt.h f8609e5a04eec2e89f35520b31c0b506ef905a3485f09b4dc4e20583743cee31 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1a54743a3d327efc8ecc45b9fde91ddfea3fca36408f9b753453c31f2e4cc69c 5c118617cf08e17a6edfdfba86e3fc49132a780990b68b52724c2aaeac85f506 -R 61ca5ca7599f2be6c4e9cd152abdc4cf +P 1fbd7438611174aa594485241c8cc2f4ea6d09c57ef2fc16c8995e8061fdfdd6 +R fea3b2f358faeafe90a4680ffb2fd073 U drh -Z c94abd09133b87123ef5ae9e8b7dbfb2 +Z e96baec64b302955260568266fc4d764 diff --git a/manifest.uuid b/manifest.uuid index c432a3e36c..5810853df2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1fbd7438611174aa594485241c8cc2f4ea6d09c57ef2fc16c8995e8061fdfdd6 \ No newline at end of file +9e04ba22dfce3998e61331ac229ff543ecccc590284c9dd5def21efbe594fba0 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 04dbd28798..0eb7af7f40 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3395,6 +3395,24 @@ void sqlite3ExprCodeLoadIndexColumn( } } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS +/* +** Generate code that will compute the value of generated column pCol +** and store the result in register regOut +*/ +void sqlite3ExprCodeGeneratedColumn( + Parse *pParse, + Column *pCol, + int regOut +){ + sqlite3ExprCode(pParse, pCol->pDflt, regOut); + if( pCol->affinity>=SQLITE_AFF_TEXT ){ + sqlite3VdbeAddOp4(pParse->pVdbe, OP_Affinity, regOut, 1, 0, + &pCol->affinity, 1); + } +} +#endif /* SQLITE_OMIT_GENERATED_COLUMNS */ + /* ** Generate code to extract the value of the iCol-th column of a table. */ @@ -3428,7 +3446,7 @@ void sqlite3ExprCodeGetColumnOfTable( int savedSelfTab = pParse->iSelfTab; pCol->colFlags |= COLFLAG_BUSY; pParse->iSelfTab = iTabCur+1; - sqlite3ExprCode(pParse, pTab->aCol[iCol].pDflt, regOut); + sqlite3ExprCodeGeneratedColumn(pParse, pCol, regOut); pParse->iSelfTab = savedSelfTab; pCol->colFlags &= ~COLFLAG_BUSY; } @@ -3630,7 +3648,7 @@ expr_code_doover: } pCol->colFlags |= COLFLAG_BUSY; if( pCol->colFlags & COLFLAG_NOTAVAIL ){ - sqlite3ExprCode(pParse, pCol->pDflt, iSrc); + sqlite3ExprCodeGeneratedColumn(pParse, pCol, iSrc); } pCol->colFlags &= ~(COLFLAG_BUSY|COLFLAG_NOTAVAIL); return iSrc; diff --git a/src/insert.c b/src/insert.c index 1995f9634c..be5f49c9ec 100644 --- a/src/insert.c +++ b/src/insert.c @@ -240,14 +240,14 @@ void sqlite3ComputeGeneratedColumns( if( colFlags & COLFLAG_VIRTUAL ){ /* Virtual columns go at the end */ assert( pTab->nNVCol+nv == sqlite3TableColumnToStorage(pTab,i) ); - sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, - iRegStore+pTab->nNVCol+nv); + sqlite3ExprCodeGeneratedColumn(pParse, &pTab->aCol[i], + iRegStore+pTab->nNVCol+nv); }else{ /* Stored columns go in column order */ assert( i-nv == sqlite3TableColumnToStorage(pTab,i) ); - sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore+i-nv); + sqlite3ExprCodeGeneratedColumn(pParse, &pTab->aCol[i], iRegStore+i-nv); } - colFlags &= ~COLFLAG_NOTAVAIL; + pTab->aCol[i].colFlags &= ~COLFLAG_NOTAVAIL; } if( (colFlags & COLFLAG_VIRTUAL)!=0 ) nv++; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 06464acb55..e2002810fe 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4096,6 +4096,9 @@ int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprCode(Parse*, Expr*, int); +#ifndef SQLITE_OMIT_GENERATED_COLUMNS +void sqlite3ExprCodeGeneratedColumn(Parse*, Column*, int); +#endif void sqlite3ExprCodeCopy(Parse*, Expr*, int); void sqlite3ExprCodeFactorable(Parse*, Expr*, int); int sqlite3ExprCodeAtInit(Parse*, Expr*, int); From a1a01ffb5e06c70610e34d9401ce8ca6eb6e0a7e Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 23 Oct 2019 00:31:01 +0000 Subject: [PATCH 26/31] Fix the foreign key logic to be compatible with generated columns. FossilOrigin-Name: 3de57145a18c62ff9b556c7218d8b276000d0052e4890212fa9335235f22d03c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/fkey.c | 16 +++++++++++----- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index da5bf8a3de..bc121493ef 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Take\sthe\sdeclared\scolumn\stime\sinto\saccount\swhen\scomputing\sthe\svalues\sfor\ngenerated\scolumns,\sand\sapply\sappropriate\saffinity. -D 2019-10-22T21:01:34.082 +C Fix\sthe\sforeign\skey\slogic\sto\sbe\scompatible\swith\sgenerated\scolumns. +D 2019-10-23T00:31:01.003 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -479,7 +479,7 @@ F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319 F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf F src/expr.c bf20202a8db15eda35f160df741805509be8c1e5e3258e4770e48db6e27d7994 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 -F src/fkey.c 6271fda51794b569d736eba4097d28f13080cd0c9eb66d5fcecb4b77336fae50 +F src/fkey.c ac56f02ffe7a3dff311654f86e3c2fd1ff2eb38862b0c07fd908d8cc0fb4a9a2 F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12 F src/global.c a1a8d698762ddd9a1543aac26c1e0029b20fcc3fcb56bfa41ec8cea2368f2798 F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1fbd7438611174aa594485241c8cc2f4ea6d09c57ef2fc16c8995e8061fdfdd6 -R fea3b2f358faeafe90a4680ffb2fd073 +P 9e04ba22dfce3998e61331ac229ff543ecccc590284c9dd5def21efbe594fba0 +R 4efaab9a7b4cdb038809c0556992ee41 U drh -Z e96baec64b302955260568266fc4d764 +Z 7c33f9873611248b66edeb0dcba63fe2 diff --git a/manifest.uuid b/manifest.uuid index 5810853df2..858109fa2d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9e04ba22dfce3998e61331ac229ff543ecccc590284c9dd5def21efbe594fba0 \ No newline at end of file +3de57145a18c62ff9b556c7218d8b276000d0052e4890212fa9335235f22d03c \ No newline at end of file diff --git a/src/fkey.c b/src/fkey.c index 1b86692da7..c57fb14657 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -349,7 +349,7 @@ static void fkLookupParent( VdbeCoverage(v); } for(i=0; inCol; i++){ - int iReg = aiCol[i] + regData + 1; + int iReg = sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[i]) + regData + 1; sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); VdbeCoverage(v); } @@ -365,7 +365,8 @@ static void fkLookupParent( ** is no matching parent key. Before using MustBeInt, make a copy of ** the value. Otherwise, the value inserted into the child key column ** will have INTEGER affinity applied to it, which may not be correct. */ - sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[0]+1+regData, regTemp); + sqlite3VdbeAddOp2(v, OP_SCopy, + sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[0])+1+regData, regTemp); iMustBeInt = sqlite3VdbeAddOp2(v, OP_MustBeInt, regTemp, 0); VdbeCoverage(v); @@ -392,7 +393,9 @@ static void fkLookupParent( sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); for(i=0; ipFrom, aiCol[i])+1+regData, + regTemp+i); } /* If the parent table is the same as the child table, and we are about @@ -408,8 +411,11 @@ static void fkLookupParent( if( pTab==pFKey->pFrom && nIncr==1 ){ int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1; for(i=0; iaiColumn[i]+1+regData; + int iChild = sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[i]) + +1+regData; + int iParent = 1+regData; + iParent += sqlite3TableColumnToStorage(pIdx->pTable, + pIdx->aiColumn[i]); assert( pIdx->aiColumn[i]>=0 ); assert( aiCol[i]!=pTab->iPKey ); if( pIdx->aiColumn[i]==pTab->iPKey ){ From ab0992f022b4e9ee5f0ac79a2fb6b3556e8a9cb2 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 23 Oct 2019 03:53:10 +0000 Subject: [PATCH 27/31] Fix incorrect arguments to testcase() macros. FossilOrigin-Name: 812467fbf04ce00228a8381a5eee471e4e35cc63184a4538129fcd70b7cec979 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/build.c | 4 ++-- src/insert.c | 8 ++++---- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index bc121493ef..deb7a10bbb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\sforeign\skey\slogic\sto\sbe\scompatible\swith\sgenerated\scolumns. -D 2019-10-23T00:31:01.003 +C Fix\sincorrect\sarguments\sto\stestcase()\smacros. +D 2019-10-23T03:53:10.742 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c 27c8224737b4649ea6d264e8433e66bc226a6859c8e11a2f9849516c211da4d9 +F src/build.c 7e4c835984afd813ab0511e6d2b6dad8e8dd8ecd227c58d589f36f15d588730f F src/callback.c 88615dfc0a82167b65b452b4b305dbf86be77200b3343c6ffc6d03e92a01d181 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 7ab2c74825809a7e3cb1fa5b480d052c96c939dafb449713a7a9da0d949447af +F src/insert.c aa90da6540183b60e91886648678d1ab785276c2a1b35f5d6ac6939b8c44300c F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 9e04ba22dfce3998e61331ac229ff543ecccc590284c9dd5def21efbe594fba0 -R 4efaab9a7b4cdb038809c0556992ee41 +P 3de57145a18c62ff9b556c7218d8b276000d0052e4890212fa9335235f22d03c +R a55e27ef47378211556554247e39924e U drh -Z 7c33f9873611248b66edeb0dcba63fe2 +Z fccb2616701d2c5fa9e700807faeffc4 diff --git a/manifest.uuid b/manifest.uuid index 858109fa2d..d7d25eec60 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3de57145a18c62ff9b556c7218d8b276000d0052e4890212fa9335235f22d03c \ No newline at end of file +812467fbf04ce00228a8381a5eee471e4e35cc63184a4538129fcd70b7cec979 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 5cd9473fa2..51398f16f1 100644 --- a/src/build.c +++ b/src/build.c @@ -1407,8 +1407,8 @@ void sqlite3AddDefaultValue( pCol->zName); #ifndef SQLITE_OMIT_GENERATED_COLUMNS }else if( pCol->colFlags & COLFLAG_GENERATED ){ - testcase( pCol->colflags & COLFLAG_VIRTUAL ); - testcase( pCol->colflags & COLFLAG_STORED ); + testcase( pCol->colFlags & COLFLAG_VIRTUAL ); + testcase( pCol->colFlags & COLFLAG_STORED ); sqlite3ErrorMsg(pParse, "cannot use DEFAULT on a generated column"); #endif }else{ diff --git a/src/insert.c b/src/insert.c index be5f49c9ec..5b2505b2c8 100644 --- a/src/insert.c +++ b/src/insert.c @@ -222,8 +222,8 @@ void sqlite3ComputeGeneratedColumns( */ for(i=0; inCol; i++){ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ - testcase( pTab->aCol[i].colflags & COLFLAG_VIRTUAL ); - testcase( pTab->aCol[i].colflags & COLFLAG_STORED ); + testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ); + testcase( pTab->aCol[i].colFlags & COLFLAG_STORED ); pTab->aCol[i].colFlags |= COLFLAG_NOTAVAIL; } } @@ -2440,8 +2440,8 @@ static int xferOptimization( /* Generator expressions for generated columns must match */ if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){ if( sqlite3ExprCompare(0, pSrcCol->pDflt, pDestCol->pDflt, -1)!=0 ){ - testcase( pDestCol->colflags & COLFLAG_VIRTUAL ); - testcase( pDestCol->colflags & COLFLAG_STORED ); + testcase( pDestCol->colFlags & COLFLAG_VIRTUAL ); + testcase( pDestCol->colFlags & COLFLAG_STORED ); return 0; /* Different generator expressions */ } } From 6ab61d7052d3d384e18f99af8dc4d70b42f93153 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 23 Oct 2019 15:47:33 +0000 Subject: [PATCH 28/31] Minor adjustments for clarity and test coverage. FossilOrigin-Name: 30065716878d4058e75eb510b0b27b68e5193d04625eb173210de8061f20f499 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/build.c | 2 +- src/insert.c | 45 +++++++++++++++++++++++++++++++++------------ src/resolve.c | 2 +- src/update.c | 4 ++-- src/vdbe.c | 1 - 7 files changed, 48 insertions(+), 28 deletions(-) diff --git a/manifest b/manifest index deb7a10bbb..102c2bdc79 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sincorrect\sarguments\sto\stestcase()\smacros. -D 2019-10-23T03:53:10.742 +C Minor\sadjustments\sfor\sclarity\sand\stest\scoverage. +D 2019-10-23T15:47:33.769 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c 7e4c835984afd813ab0511e6d2b6dad8e8dd8ecd227c58d589f36f15d588730f +F src/build.c f7070af66656b75be79a79a8ac720f4f0f8b48ba56298f2d9bf0f982d07ed949 F src/callback.c 88615dfc0a82167b65b452b4b305dbf86be77200b3343c6ffc6d03e92a01d181 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -486,7 +486,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c aa90da6540183b60e91886648678d1ab785276c2a1b35f5d6ac6939b8c44300c +F src/insert.c 54425efd1d2ce8715907d3df7341adc55173769b7b279f85c015bbeb36a82389 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66 @@ -523,7 +523,7 @@ F src/pragma.h 40962d65b645bb3f08c1f4c456effd01c6e7f073f68ea25177e0c95e181cff75 F src/prepare.c 6049beb71385f017af6fc320d2c75a4e50b75e280c54232442b785fbb83df057 F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 -F src/resolve.c 2160146697e6e0ba251b5a954e16f542b6e684fb4778cec2994094ab401ef996 +F src/resolve.c 9d6a3bdca1ebc759c4616fee0d7dd4cf62741f53db3a6b0117600f27c5b1406a F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c 9c81d168b5a7ddc2277a6f6d3daec9ddd0ff5cebf12628d7e342f3c337231e7e F src/shell.c.in 3093bdf5eedd91da08f0268f1442aa510a60798c9441868149ddbecdf8bcaa79 @@ -592,12 +592,12 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c 7b17f6e2f20f6cbcb0b215025a86b7457c38451fc7622f705e553d7a488c572d F src/treeview.c fddeb413159c3eeeaea3f496172f121cf3695606c461dc4e6dcee51417952df5 F src/trigger.c 845ccc08f60716c58aa28fe6470385c18ef8c4e1d88c93dcf449bc13d464eb2e -F src/update.c 3a5e1fa8e29413ee633f049bf9f0e1eb33a03a53cb55b6ea290120b324fbf46e +F src/update.c ae657f0db6a255011759ab9345ded7b54b828329a9dba04f94b4d4fa6e70e1ad F src/upsert.c b445315c8958d8f17ec3297d06842e61dacaad0633ccaec1e4e160de7e562212 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507 F src/util.c 10d910e04a4f3842042485e0df01a484f57f912c10b60b3a09ccddd5019bd138 F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf -F src/vdbe.c 9a3f4c2ec6c45e4bd5db465e77e79dfdf5bdc5cf3a8c0bfe9549da209b9c18bc +F src/vdbe.c 9e4ba6bb8e5b827b9ae771ba62a92f3099adaacd36838d54042eb2499cd7f6f5 F src/vdbe.h b02904e1bd45c26fdf00c04844b9cfa825763aa5150b6d89ce88b8ab03581d0a F src/vdbeInt.h bd589b8b7273286858950717e0e1ec5c88b18af45079a3366dc1371865cea704 F src/vdbeapi.c 1252d80c548711e47a6d84dae88ed4e95d3fbb4e7bd0eaa1347299af7efddf02 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 3de57145a18c62ff9b556c7218d8b276000d0052e4890212fa9335235f22d03c -R a55e27ef47378211556554247e39924e +P 812467fbf04ce00228a8381a5eee471e4e35cc63184a4538129fcd70b7cec979 +R f0b4a76631d2a0cb79112ae41777ee3f U drh -Z fccb2616701d2c5fa9e700807faeffc4 +Z 9a9ae7faa8a1962c89b9945fd49858aa diff --git a/manifest.uuid b/manifest.uuid index d7d25eec60..37b0f6f9cd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -812467fbf04ce00228a8381a5eee471e4e35cc63184a4538129fcd70b7cec979 \ No newline at end of file +30065716878d4058e75eb510b0b27b68e5193d04625eb173210de8061f20f499 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 51398f16f1..ecf54fe8cd 100644 --- a/src/build.c +++ b/src/build.c @@ -1628,7 +1628,7 @@ void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){ u8 eType = COLFLAG_VIRTUAL; Table *pTab = pParse->pNewTable; Column *pCol; - if( pTab==0 ) goto generated_done; + if( NEVER(pTab==0) ) goto generated_done; pCol = &(pTab->aCol[pTab->nCol-1]); if( IN_DECLARE_VTAB ){ sqlite3ErrorMsg(pParse, "virtual tables cannot use computed columns"); diff --git a/src/insert.c b/src/insert.c index 5b2505b2c8..b6fdc3927e 100644 --- a/src/insert.c +++ b/src/insert.c @@ -857,13 +857,13 @@ void sqlite3Insert( if( pColumn==0 && nColumn>0 ){ ipkColumn = pTab->iPKey; #ifndef SQLITE_OMIT_GENERATED_COLUMNS - if( pTab->tabFlags & TF_HasGenerated ){ + if( ipkColumn>=0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){ testcase( pTab->tabFlags & TF_HasVirtual ); - testcase( pTab->tabFlags & TF_HasGenerated ); + testcase( pTab->tabFlags & TF_HasStored ); for(i=ipkColumn-1; i>=0; i--){ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){ testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ); - testcase( pTab->aCol[i].colFlags & COLFLAG_GENERATED ); + testcase( pTab->aCol[i].colFlags & COLFLAG_STORED ); ipkColumn--; } } @@ -2413,10 +2413,39 @@ static int xferOptimization( return 0; /* Neither table may have __hidden__ columns */ } #endif +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + /* Even if tables t1 and t2 have identical schemas, if they contain + ** generated columns, then this statement is semantically incorrect: + ** + ** INSERT INTO t2 SELECT * FROM t1; + ** + ** The reason is that generated column values are returned by the + ** the SELECT statement on the right but the INSERT statement on the + ** left wants them to be omitted. + ** + ** Nevertheless, this is a useful notational shorthand to tell SQLite + ** to do a bulk transfer all of the content from t1 over to t2. + ** + ** We could, in theory, disable this (except for internal use by the + ** VACUUM command where it is actually needed). But why do that? It + ** seems harmless enough, and provides a useful service. + */ if( (pDestCol->colFlags & COLFLAG_GENERATED) != (pSrcCol->colFlags & COLFLAG_GENERATED) ){ - return 0; /* Both columns have the same generated type */ + return 0; /* Both columns have the same generated-column type */ } + /* But the transfer is only allowed if both the source and destination + ** tables have the exact same expressions for generated columns. + ** This requirement could be relaxed for VIRTUAL columns, I suppose. + */ + if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){ + if( sqlite3ExprCompare(0, pSrcCol->pDflt, pDestCol->pDflt, -1)!=0 ){ + testcase( pDestCol->colFlags & COLFLAG_VIRTUAL ); + testcase( pDestCol->colFlags & COLFLAG_STORED ); + return 0; /* Different generator expressions */ + } + } +#endif if( pDestCol->affinity!=pSrcCol->affinity ){ return 0; /* Affinity must be the same on all columns */ } @@ -2437,14 +2466,6 @@ static int xferOptimization( return 0; /* Default values must be the same for all columns */ } } - /* Generator expressions for generated columns must match */ - if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){ - if( sqlite3ExprCompare(0, pSrcCol->pDflt, pDestCol->pDflt, -1)!=0 ){ - testcase( pDestCol->colFlags & COLFLAG_VIRTUAL ); - testcase( pDestCol->colFlags & COLFLAG_STORED ); - return 0; /* Different generator expressions */ - } - } } for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ if( IsUniqueIndex(pDestIdx) ){ diff --git a/src/resolve.c b/src/resolve.c index 657746842d..a9c20b1016 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -633,7 +633,7 @@ static void notValid( else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints"; #endif #ifndef SQLITE_OMIT_GENERATED_COLUMNS - else if( pNC->ncFlags & NC_GenCol ) zIn = "GENERATED ALWAYS AS columns"; + else if( pNC->ncFlags & NC_GenCol ) zIn = "generated columns"; #endif sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn); } diff --git a/src/update.c b/src/update.c index d690b69f95..816a6818be 100644 --- a/src/update.c +++ b/src/update.c @@ -314,8 +314,8 @@ void sqlite3Update( } #ifndef SQLITE_OMIT_GENERATED_COLUMNS else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){ - testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ); - testcase( pTab->aCol[i].colFlags & COLFLAG_STORED ); + testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ); + testcase( pTab->aCol[j].colFlags & COLFLAG_STORED ); sqlite3ErrorMsg(pParse, "cannot UPDATE generated column \"%s\"", pTab->aCol[j].zName); diff --git a/src/vdbe.c b/src/vdbe.c index 1082b13d14..7c8d2a4ef7 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -3375,7 +3375,6 @@ case OP_AutoCommit: { p->rc = rc = SQLITE_BUSY; goto vdbe_return; } - assert( db->nStatement==0 ); sqlite3CloseSavepoints(db); if( p->rc==SQLITE_OK ){ rc = SQLITE_DONE; From 035f6d909fcdd2b36320b07aec608a6c75187593 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 24 Oct 2019 01:04:10 +0000 Subject: [PATCH 29/31] Do not allow ALTER TABLE ADD COLUMN for a STORED column. FossilOrigin-Name: 42fc08bc1528a34a603c2c085b515766a8d33ae7ea0350a52b0ca24b94ebcbc5 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/alter.c | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 102c2bdc79..c2f6adb666 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\sadjustments\sfor\sclarity\sand\stest\scoverage. -D 2019-10-23T15:47:33.769 +C Do\snot\sallow\sALTER\sTABLE\sADD\sCOLUMN\sfor\sa\sSTORED\scolumn. +D 2019-10-24T01:04:10.370 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -459,7 +459,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c fa7486bfd12be8c8a0d4425767fa42203ca9e946c9613bb37924643c622706bf +F src/alter.c 0fdf14a1d1c61315a6d727252c579bc8cbfe62de195df6979dd784374e22032b F src/analyze.c fd70b9c7a683230a7f7936af64dd25308e93d7c9819a3168493a7c7703481f80 F src/attach.c 3ca19504849c2d9be10fc5899d6811f9d6e848665d1a41ffb53df0cd6e7c13ed F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 812467fbf04ce00228a8381a5eee471e4e35cc63184a4538129fcd70b7cec979 -R f0b4a76631d2a0cb79112ae41777ee3f +P 30065716878d4058e75eb510b0b27b68e5193d04625eb173210de8061f20f499 +R 7202e3e1ab0c99bc839229fb4e803cbe U drh -Z 9a9ae7faa8a1962c89b9945fd49858aa +Z 98506792ef3b33ac52584457b01d83d1 diff --git a/manifest.uuid b/manifest.uuid index 37b0f6f9cd..9afd35a970 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -30065716878d4058e75eb510b0b27b68e5193d04625eb173210de8061f20f499 \ No newline at end of file +42fc08bc1528a34a603c2c085b515766a8d33ae7ea0350a52b0ca24b94ebcbc5 \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index b7389bf9cb..0a82327d63 100644 --- a/src/alter.c +++ b/src/alter.c @@ -349,6 +349,9 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ } sqlite3ValueFree(pVal); } + }else if( pCol->colFlags & COLFLAG_STORED ){ + sqlite3ErrorMsg(pParse, "cannot add a STORED column"); + return; } From c7476735c9b9e377958ab404f0130f3f43a219dc Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 24 Oct 2019 20:29:25 +0000 Subject: [PATCH 30/31] Fix handling of covering indexes that use virtual columns. FossilOrigin-Name: e0f7e321eca91c49102649f70728de69347cbd7b16599b854203c24cfdc348e6 --- manifest | 16 +++++++-------- manifest.uuid | 2 +- src/build.c | 20 ++++++++++++++++--- src/sqliteInt.h | 1 + src/wherecode.c | 52 ++++++++++++++++++++++++++++++++++++++++++------- 5 files changed, 72 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index c2f6adb666..ef84588b6f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sallow\sALTER\sTABLE\sADD\sCOLUMN\sfor\sa\sSTORED\scolumn. -D 2019-10-24T01:04:10.370 +C Fix\shandling\sof\scovering\sindexes\sthat\suse\svirtual\scolumns. +D 2019-10-24T20:29:25.035 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -469,7 +469,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c a8a9c2ce62bdf54c8cf9795143d7cb10b7473a1230a0572f702d061ffcceefe5 F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484 F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437 -F src/build.c f7070af66656b75be79a79a8ac720f4f0f8b48ba56298f2d9bf0f982d07ed949 +F src/build.c 0c9704f95817aa585fdad2668c611280d0b62bc4c1c836cd1c797ba96879a7d6 F src/callback.c 88615dfc0a82167b65b452b4b305dbf86be77200b3343c6ffc6d03e92a01d181 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251 @@ -530,7 +530,7 @@ F src/shell.c.in 3093bdf5eedd91da08f0268f1442aa510a60798c9441868149ddbecdf8bcaa7 F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31 -F src/sqliteInt.h f8609e5a04eec2e89f35520b31c0b506ef905a3485f09b4dc4e20583743cee31 +F src/sqliteInt.h 5b2d25ba23135ece06886d82f60d9a16869506592e5950f3c09257b3b5d28d5c F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -613,7 +613,7 @@ F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a F src/walker.c d5a94907dcac990e31976be9dc769d17f6a806782593d6aec9d760ee01ec22cd F src/where.c 6ff3ef076485dd71efbbabcc7ddc0473c04a9bdcb524128939757b002466f2d1 F src/whereInt.h 4a296fd4fa79fdcbc2b5e8c1b898901617655811223e1082b899c23ecb092217 -F src/wherecode.c d96190c0b536339375846048ad3c41758b4bd6baaf8f8f350da5911d42bc4a61 +F src/wherecode.c c491ae0ce1de97bc4eea566350a2d1e7c2c5fcf97b9d4c89593c4f068e21a30d F src/whereexpr.c 0705f608f6dbbd4e95d440528d6c760b91b6f402ba4eb8b8d964c110e2010780 F src/window.c 064f251451c8e2a1c76b6269229d911a651e119c6a5f522b6eaebf8dc8714041 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 30065716878d4058e75eb510b0b27b68e5193d04625eb173210de8061f20f499 -R 7202e3e1ab0c99bc839229fb4e803cbe +P 42fc08bc1528a34a603c2c085b515766a8d33ae7ea0350a52b0ca24b94ebcbc5 +R 6a9e8fc570824aa923ac6838bd994212 U drh -Z 98506792ef3b33ac52584457b01d83d1 +Z b5f3ce7a354e5714077f87bfe3d7f12c diff --git a/manifest.uuid b/manifest.uuid index 9afd35a970..7f612f17c0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -42fc08bc1528a34a603c2c085b515766a8d33ae7ea0350a52b0ca24b94ebcbc5 \ No newline at end of file +e0f7e321eca91c49102649f70728de69347cbd7b16599b854203c24cfdc348e6 \ No newline at end of file diff --git a/src/build.c b/src/build.c index ecf54fe8cd..84440af676 100644 --- a/src/build.c +++ b/src/build.c @@ -1923,15 +1923,24 @@ static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){ ** high-order bit of colNotIdxed is always 1. All unindexed columns ** of the table have a 1. ** +** 2019-10-24: For the purpose of this computation, virtual columns are +** not considered to be covered by the index, even if they are in the +** index, because we do not trust the logic in whereIndexExprTrans() to be +** able to find all instances of a reference to the indexed table column +** and convert them into references to the index. Hence we always want +** the actual table at hand in order to recompute the virtual column, if +** necessary. +** ** The colNotIdxed mask is AND-ed with the SrcList.a[].colUsed mask ** to determine if the index is covering index. */ static void recomputeColumnsNotIndexed(Index *pIdx){ Bitmask m = 0; int j; + Table *pTab = pIdx->pTable; for(j=pIdx->nColumn-1; j>=0; j--){ int x = pIdx->aiColumn[j]; - if( x>=0 ){ + if( x>=0 && (pTab->aCol[x].colFlags & COLFLAG_VIRTUAL)==0 ){ testcase( x==BMS-1 ); testcase( x==BMS-2 ); if( xiPKey; - }else if( pTab->aCol[j].notNull==0 ){ - pIndex->uniqNotNull = 0; + }else{ + if( pTab->aCol[j].notNull==0 ){ + pIndex->uniqNotNull = 0; + } + if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){ + pIndex->bHasVCol = 1; + } } pIndex->aiColumn[i] = (i16)j; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e2002810fe..d8668a278f 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2295,6 +2295,7 @@ struct Index { unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ unsigned bNoQuery:1; /* Do not use this index to optimize queries */ unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ + unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ #ifdef SQLITE_ENABLE_STAT4 int nSample; /* Number of elements in aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ diff --git a/src/wherecode.c b/src/wherecode.c index 686a8d6f9a..0438cca54a 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -1106,6 +1106,7 @@ typedef struct IdxExprTrans { int iTabCur; /* The cursor of the corresponding table */ int iIdxCur; /* The cursor for the index */ int iIdxCol; /* The column for the index */ + int iTabCol; /* The column for the table */ } IdxExprTrans; /* The walker node callback used to transform matching expressions into @@ -1128,10 +1129,30 @@ static int whereIndexExprTransNode(Walker *p, Expr *pExpr){ } } +#ifndef SQLITE_OMIT_GENERATED_COLUMNS +/* A walker node callback that translates a column reference to a table +** into a corresponding column reference of an index. +*/ +static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){ + if( pExpr->op==TK_COLUMN ){ + IdxExprTrans *pX = p->u.pIdxTrans; + if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){ + pExpr->iTable = pX->iIdxCur; + pExpr->iColumn = pX->iIdxCol; + } + } + return WRC_Continue; +} +#endif /* SQLITE_OMIT_GENERATED_COLUMNS */ + /* ** For an indexes on expression X, locate every instance of expression X ** in pExpr and change that subexpression into a reference to the appropriate ** column of the index. +** +** 2019-10-24: Updated to also translate references to a VIRTUAL column in +** the table into references to the corresponding (stored) column of the +** index. */ static void whereIndexExprTrans( Index *pIdx, /* The Index */ @@ -1141,20 +1162,35 @@ static void whereIndexExprTrans( ){ int iIdxCol; /* Column number of the index */ ExprList *aColExpr; /* Expressions that are indexed */ + Table *pTab; Walker w; IdxExprTrans x; aColExpr = pIdx->aColExpr; - if( aColExpr==0 ) return; /* Not an index on expressions */ + if( aColExpr==0 && !pIdx->bHasVCol ){ + /* The index does not reference any expressions or virtual columns + ** so no translations are needed. */ + return; + } + pTab = pIdx->pTable; memset(&w, 0, sizeof(w)); - w.xExprCallback = whereIndexExprTransNode; w.u.pIdxTrans = &x; x.iTabCur = iTabCur; x.iIdxCur = iIdxCur; - for(iIdxCol=0; iIdxColnExpr; iIdxCol++){ - if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue; - assert( aColExpr->a[iIdxCol].pExpr!=0 ); + for(iIdxCol=0; iIdxColnColumn; iIdxCol++){ + i16 iRef = pIdx->aiColumn[iIdxCol]; + if( iRef==XN_EXPR ){ + assert( aColExpr->a[iIdxCol].pExpr!=0 ); + x.pIdxExpr = aColExpr->a[iIdxCol].pExpr; + w.xExprCallback = whereIndexExprTransNode; +#ifndef SQLITE_OMIT_GENERATED_COLUMNS + }else if( iRef>=0 && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0 ){ + x.iTabCol = iRef; + w.xExprCallback = whereIndexExprTransColumn; +#endif /* SQLITE_OMIT_GENERATED_COLUMNS */ + }else{ + continue; + } x.iIdxCol = iIdxCol; - x.pIdxExpr = aColExpr->a[iIdxCol].pExpr; sqlite3WalkExpr(&w, pWInfo->pWhere); sqlite3WalkExprList(&w, pWInfo->pOrderBy); sqlite3WalkExprList(&w, pWInfo->pResultSet); @@ -1835,7 +1871,9 @@ Bitmask sqlite3WhereCodeOneLoopStart( /* If pIdx is an index on one or more expressions, then look through ** all the expressions in pWInfo and try to transform matching expressions - ** into reference to index columns. + ** into reference to index columns. Also attempt to translate references + ** to virtual columns in the table into references to (stored) columns + ** of the index. ** ** Do not do this for the RHS of a LEFT JOIN. This is because the ** expression may be evaluated after OP_NullRow has been executed on From 4485ac1a25e9919b5911a0db2ad7bed58be143d6 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 24 Oct 2019 21:02:06 +0000 Subject: [PATCH 31/31] The previous fix was incomplete. It is also necessary to disable the Expr.y.pTab field when making the translation. FossilOrigin-Name: b99d5701312f7472e6b606bd824f9273617e2655920485bf50aa96d408064721 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/wherecode.c | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index ef84588b6f..72ada93e96 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\shandling\sof\scovering\sindexes\sthat\suse\svirtual\scolumns. -D 2019-10-24T20:29:25.035 +C The\sprevious\sfix\swas\sincomplete.\s\sIt\sis\salso\snecessary\sto\sdisable\sthe\nExpr.y.pTab\sfield\swhen\smaking\sthe\stranslation. +D 2019-10-24T21:02:06.779 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -613,7 +613,7 @@ F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a F src/walker.c d5a94907dcac990e31976be9dc769d17f6a806782593d6aec9d760ee01ec22cd F src/where.c 6ff3ef076485dd71efbbabcc7ddc0473c04a9bdcb524128939757b002466f2d1 F src/whereInt.h 4a296fd4fa79fdcbc2b5e8c1b898901617655811223e1082b899c23ecb092217 -F src/wherecode.c c491ae0ce1de97bc4eea566350a2d1e7c2c5fcf97b9d4c89593c4f068e21a30d +F src/wherecode.c 28a3f27b44165e05bac3031f9a9ee9901305647b6c9dfc0214544578066ab097 F src/whereexpr.c 0705f608f6dbbd4e95d440528d6c760b91b6f402ba4eb8b8d964c110e2010780 F src/window.c 064f251451c8e2a1c76b6269229d911a651e119c6a5f522b6eaebf8dc8714041 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1847,7 +1847,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 42fc08bc1528a34a603c2c085b515766a8d33ae7ea0350a52b0ca24b94ebcbc5 -R 6a9e8fc570824aa923ac6838bd994212 +P e0f7e321eca91c49102649f70728de69347cbd7b16599b854203c24cfdc348e6 +R fd3794f20216cf9a398f8319df03644c U drh -Z b5f3ce7a354e5714077f87bfe3d7f12c +Z 2a2696445dbabbaa1fdad14d659304f0 diff --git a/manifest.uuid b/manifest.uuid index 7f612f17c0..7d09a5409c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e0f7e321eca91c49102649f70728de69347cbd7b16599b854203c24cfdc348e6 \ No newline at end of file +b99d5701312f7472e6b606bd824f9273617e2655920485bf50aa96d408064721 \ No newline at end of file diff --git a/src/wherecode.c b/src/wherecode.c index 0438cca54a..351af766e6 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -1139,6 +1139,7 @@ static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){ if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){ pExpr->iTable = pX->iIdxCur; pExpr->iColumn = pX->iIdxCol; + pExpr->y.pTab = 0; } } return WRC_Continue;