Add support for generated columns.
FossilOrigin-Name: b855acf1831943b3914491ed0bc333131321930cab480a5281012a3aebbba492
This commit is contained in:
commit
a88c8c1ae4
51
manifest
51
manifest
@ -1,5 +1,5 @@
|
||||
C Performance\soptimization\son\ssqlite3GenerateConstraintChecks()\s-\sbypass\sthe\nloop\sthat\schecks\seach\scolumn\sfor\sNOT\sNULL\sconstraints\sif\sit\sis\sknown\sin\nadvance\sthat\sthe\stable\shas\sno\sNOT\sNULL\sconstraints.
|
||||
D 2019-10-26T17:08:06.316
|
||||
C Add\ssupport\sfor\sgenerated\scolumns.
|
||||
D 2019-10-26T18:47:47.117
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -460,8 +460,8 @@ 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/analyze.c 481d9cf34a3c70631ef5c416be70033e8d4cd85eb5ad1b37286aed8b0e29e889
|
||||
F src/alter.c 0fdf14a1d1c61315a6d727252c579bc8cbfe62de195df6979dd784374e22032b
|
||||
F src/analyze.c fd70b9c7a683230a7f7936af64dd25308e93d7c9819a3168493a7c7703481f80
|
||||
F src/attach.c 3ca19504849c2d9be10fc5899d6811f9d6e848665d1a41ffb53df0cd6e7c13ed
|
||||
F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06
|
||||
F src/backup.c f70077d40c08b7787bfe934e4d1da8030cb0cc57d46b345fba2294b7d1be23ab
|
||||
@ -470,7 +470,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c 12e251f8c3eaad05e6d0db94772bf779b3a644e18d884025da6bcbc98cad1d22
|
||||
F src/btree.h f27a33c49280209a93385e218306c4ee5f46ba8d7649d2f81a7166b282232484
|
||||
F src/btreeInt.h 91806f01fd1145a9a86ba3042f25c38d8faf6002701bf5e780742cf88bcff437
|
||||
F src/build.c 2e17f27da8ff7bb52cd23dbd6a8c7269babf11bb1beae08e470c5b0f4b077801
|
||||
F src/build.c 3dea3b75107c83243b8b2244334c3c574865a12d33d0b86d345123f4dc1ca8d6
|
||||
F src/callback.c 88615dfc0a82167b65b452b4b305dbf86be77200b3343c6ffc6d03e92a01d181
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 1b0724e66f95f33b160b1af85caaf9cceb325d22abf39bd24df4f54a73982251
|
||||
@ -478,16 +478,16 @@ F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041
|
||||
F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
|
||||
F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319
|
||||
F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf
|
||||
F src/expr.c afa8c1082e1bbcf68673deabd973504f0f975162c910d39f04806439f20b3657
|
||||
F src/expr.c 91429fb52958fd2ff0f5360a2cc9f41dd811dc8666d22cbb033f1557dd5fdbc2
|
||||
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
|
||||
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
|
||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 09e64dd9394a06bb25e54180312f16932c98643b53f576a7dd3b9344a635cf2c
|
||||
F src/insert.c 948bbd90277450f8d4f9ba4b881dd6676023d9e8bad56228064184dc85011cca
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 4ddc65ae13c0d93db0ceedc8b14a28c8c260513448b0eb8c5a2ac375e3b6a85d
|
||||
F src/main.c 3e01f6a1c96643381b5f9d79e4ff7f2520bc5712197746fb0852283e78cccf66
|
||||
@ -515,23 +515,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 72886e0ce14abd97351b0e4414f0c734ca397afa9b224334bd099edb978a6788
|
||||
F src/parse.y 97d46c41ea4185e8711560d7484cf5b4887fd2317dec79637be23454b5147647
|
||||
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
|
||||
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
||||
F src/pcache1.c 62714cbd1b7299a6e6a27a587b66b4fd3a836a84e1181e7f96f5c34a50917848
|
||||
F src/pragma.c b47bc7db02ab13d04c680aee424466b4e34f4ef5aa7b2e464876ec005806f98f
|
||||
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 e021be0c1c4a2125fa38aabcd8dbb764bf5b2c889a948c30d3708430ec6ccd00
|
||||
F src/resolve.c 9d6a3bdca1ebc759c4616fee0d7dd4cf62741f53db3a6b0117600f27c5b1406a
|
||||
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
|
||||
F src/select.c 3395765ea3749341deb4c25e8339c3d626a8ac641a52c216e9632e48e620ba68
|
||||
F src/shell.c.in 01d14c1e0a4dc45b6029baf1aa560de92b6b12c05a87e2270c1e4fc41ca0fd1e
|
||||
F src/sqlite.h.in 5725a6b20190a1e8d662077a1c1c8ea889ad7be90dd803f914c2de226f5fe6ab
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h cef696ce3293242c67b2339763608427bf72ee66f1f3a05389ac2a7b46001c31
|
||||
F src/sqliteInt.h 5e98328254a8932a912cd12960cc7a4f22078a56bc9c617ffe042ad554c0db68
|
||||
F src/sqliteInt.h 5b2d25ba23135ece06886d82f60d9a16869506592e5950f3c09257b3b5d28d5c
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
@ -593,28 +593,28 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 7b17f6e2f20f6cbcb0b215025a86b7457c38451fc7622f705e553d7a488c572d
|
||||
F src/treeview.c 19e660b3a4ff8ae7dda426795020f0d2e1b349fa8cad19af9c9bf2a9063f2ef9
|
||||
F src/trigger.c 845ccc08f60716c58aa28fe6470385c18ef8c4e1d88c93dcf449bc13d464eb2e
|
||||
F src/update.c 1487ee46b6ec36c59fe2c127b6f7daa88daaaf6e58eee8c441377f9b9fb5a684
|
||||
F src/upsert.c 710c91bb13e3c3fed5b6fe17cb13e09560bdd003ad8b8c51e6b16c80cfc48b10
|
||||
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.h 7fbde1e64423368d7fd9b606dcde1c90eb24f6f7ea1f625d161731ac2f703fca
|
||||
F src/vdbe.c 9e4ba6bb8e5b827b9ae771ba62a92f3099adaacd36838d54042eb2499cd7f6f5
|
||||
F src/vdbe.h 2a49df699f305afa94f338f14bf6e1bfbca8112ce9c4d522abffd9493fc22a25
|
||||
F src/vdbeInt.h bd589b8b7273286858950717e0e1ec5c88b18af45079a3366dc1371865cea704
|
||||
F src/vdbeapi.c 95001d0f84ee3cda344fed98ca0d7961deb4fc836b83495630d0af1f7cc4789e
|
||||
F src/vdbeaux.c be3e250525e4a75f82a8cfa0dcfe2e9cad058cf16c8c568677c2b13043db1e2d
|
||||
F src/vdbeapi.c 1252d80c548711e47a6d84dae88ed4e95d3fbb4e7bd0eaa1347299af7efddf02
|
||||
F src/vdbeaux.c e3ed5475d4611f28f3cad06c0454a354148f3bb0ce21c75659ce737dc13f7968
|
||||
F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
|
||||
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
|
||||
F src/walker.c d5a94907dcac990e31976be9dc769d17f6a806782593d6aec9d760ee01ec22cd
|
||||
F src/where.c 148fa1ce9d6421a2c325291cae7681b3492cf1f219ff58f9ef38695a7f3c61ff
|
||||
F src/where.c 6ff3ef076485dd71efbbabcc7ddc0473c04a9bdcb524128939757b002466f2d1
|
||||
F src/whereInt.h 4a296fd4fa79fdcbc2b5e8c1b898901617655811223e1082b899c23ecb092217
|
||||
F src/wherecode.c 57d034a0dbca9f86e1a691f74e469ed09ff49d04712b838fb68596b76a9af7d2
|
||||
F src/wherecode.c 28a3f27b44165e05bac3031f9a9ee9901305647b6c9dfc0214544578066ab097
|
||||
F src/whereexpr.c 0705f608f6dbbd4e95d440528d6c760b91b6f402ba4eb8b8d964c110e2010780
|
||||
F src/window.c 064f251451c8e2a1c76b6269229d911a651e119c6a5f522b6eaebf8dc8714041
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
@ -1776,7 +1776,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
|
||||
@ -1848,7 +1848,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 8c0042bd5ccd83f8794d19cbb1ec7564584f0dce54bfebc0ada00b836aca065f
|
||||
R ea2c4191b4b2904c1eb46d03fcd394de
|
||||
P e3c3f4d7872f431a95627d52553101388c1e39458cc7e7f93fc81255f49a89a5 4ec57d88415fa4ea2e99d4a5671074ec6829d6824bc8509d5ae9c978d47d1419
|
||||
R f145bc7e6a3c49b3acdcdeb1a4214a2e
|
||||
T +closed 4ec57d88415fa4ea2e99d4a5671074ec6829d6824bc8509d5ae9c978d47d1419
|
||||
U drh
|
||||
Z 5817472d3119aa1dc0ce67b1f895a616
|
||||
Z 906ad86e78e219feca2ac3d876e5c4a1
|
||||
|
@ -1 +1 @@
|
||||
e3c3f4d7872f431a95627d52553101388c1e39458cc7e7f93fc81255f49a89a5
|
||||
b855acf1831943b3914491ed0bc333131321930cab480a5281012a3aebbba492
|
29
src/alter.c
29
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,6 +311,15 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column");
|
||||
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");
|
||||
@ -343,11 +344,16 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
return;
|
||||
}
|
||||
if( !pVal ){
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default");
|
||||
sqlite3ErrorMsg(pParse,"Cannot add a column with non-constant default");
|
||||
return;
|
||||
}
|
||||
sqlite3ValueFree(pVal);
|
||||
}
|
||||
}else if( pCol->colFlags & COLFLAG_STORED ){
|
||||
sqlite3ErrorMsg(pParse, "cannot add a STORED column");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Modify the CREATE TABLE statement. */
|
||||
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
|
||||
@ -1331,6 +1337,11 @@ static void renameColumnFunc(
|
||||
sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
for(i=0; i<sParse.pNewTable->nCol; i++){
|
||||
sqlite3WalkExpr(&sWalker, sParse.pNewTable->aCol[i].pDflt);
|
||||
}
|
||||
#endif
|
||||
|
||||
for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
||||
for(i=0; i<pFKey->nCol; i++){
|
||||
|
@ -1182,7 +1182,7 @@ static void analyzeOneTable(
|
||||
int j, k, regKey;
|
||||
regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
||||
for(j=0; j<pPk->nKeyCol; j++){
|
||||
k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
|
||||
k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
|
||||
assert( k>=0 && k<pIdx->nColumn );
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
|
||||
VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
|
||||
|
212
src/build.c
212
src/build.c
@ -877,10 +877,12 @@ Index *sqlite3PrimaryKeyIndex(Table *pTab){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the column of index pIdx that corresponds to table
|
||||
** 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; i<pIdx->nColumn; i++){
|
||||
if( iCol==pIdx->aiColumn[i] ) return i;
|
||||
@ -888,6 +890,82 @@ i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
/* 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 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.
|
||||
*/
|
||||
i16 sqlite3StorageColumnToTable(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 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. 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.
|
||||
**
|
||||
** The true column number is the index (0,1,2,...) of the column in
|
||||
** the CREATE TABLE statement.
|
||||
**
|
||||
** 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;
|
||||
i16 n;
|
||||
assert( iCol<pTab->nCol );
|
||||
if( (pTab->tabFlags & TF_HasVirtual)==0 ) return iCol;
|
||||
for(i=0, n=0; i<iCol; i++){
|
||||
if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) 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
|
||||
|
||||
/*
|
||||
** Begin constructing a new table representation in memory. This is
|
||||
** the first of several action routines that get called in response
|
||||
@ -1178,6 +1256,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
|
||||
pCol->colFlags |= COLFLAG_HASTYPE;
|
||||
}
|
||||
p->nCol++;
|
||||
p->nNVCol++;
|
||||
pParse->constraintName.n = 0;
|
||||
}
|
||||
|
||||
@ -1326,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.
|
||||
@ -1371,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
|
||||
@ -1410,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;
|
||||
@ -1423,7 +1523,7 @@ void sqlite3AddPrimaryKey(
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
|
||||
pCol = &pTab->aCol[iCol];
|
||||
pCol->colFlags |= COLFLAG_PRIMKEY;
|
||||
makeColumnPartOfPrimaryKey(pParse, pCol);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1520,6 +1620,52 @@ 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( NEVER(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 ){
|
||||
/* no-op */
|
||||
}else if( pType->n==6 && sqlite3StrNICmp("stored",pType->z,6)==0 ){
|
||||
eType = COLFLAG_STORED;
|
||||
}else{
|
||||
goto generated_error;
|
||||
}
|
||||
}
|
||||
if( eType==COLFLAG_VIRTUAL ) pTab->nNVCol--;
|
||||
pCol->colFlags |= eType;
|
||||
assert( TF_HasVirtual==COLFLAG_VIRTUAL );
|
||||
assert( TF_HasStored==COLFLAG_STORED );
|
||||
pTab->tabFlags |= eType;
|
||||
pCol->pDflt = pExpr;
|
||||
pExpr = 0;
|
||||
goto generated_done;
|
||||
|
||||
generated_error:
|
||||
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 columns not supported");
|
||||
sqlite3ExprDelete(pParse->db, pExpr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will increment the schema cookie.
|
||||
**
|
||||
@ -1777,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( x<BMS-1 ) m |= MASKBIT(x);
|
||||
@ -1944,11 +2099,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
*/
|
||||
nExtra = 0;
|
||||
for(i=0; i<pTab->nCol; 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; i<pTab->nCol; i++){
|
||||
if( !hasColumn(pPk->aiColumn, j, i) ){
|
||||
if( !hasColumn(pPk->aiColumn, j, i)
|
||||
&& (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0
|
||||
){
|
||||
assert( j<pPk->nColumn );
|
||||
pPk->aiColumn[j] = i;
|
||||
pPk->azColl[j] = sqlite3StrBINARY;
|
||||
@ -1956,7 +2114,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
}
|
||||
}
|
||||
assert( pPk->nColumn==j );
|
||||
assert( pTab->nCol<=j );
|
||||
assert( pTab->nNVCol<=j );
|
||||
recomputeColumnsNotIndexed(pPk);
|
||||
}
|
||||
|
||||
@ -2065,12 +2223,11 @@ void sqlite3EndTable(
|
||||
}
|
||||
if( (p->tabFlags & TF_HasPrimaryKey)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName);
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid;
|
||||
convertToWithoutRowidTable(pParse, p);
|
||||
}
|
||||
}
|
||||
|
||||
iDb = sqlite3SchemaToIndex(db, p->pSchema);
|
||||
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
@ -2080,6 +2237,22 @@ void sqlite3EndTable(
|
||||
sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck);
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_CHECK) */
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
if( p->tabFlags & TF_HasGenerated ){
|
||||
int ii;
|
||||
testcase( p->tabFlags & TF_HasVirtual );
|
||||
testcase( p->tabFlags & TF_HasStored );
|
||||
for(ii=0; ii<p->nCol; ii++){
|
||||
u32 colFlags = p->aCol[ii].colFlags;
|
||||
if( (colFlags & COLFLAG_GENERATED)!=0 ){
|
||||
testcase( colFlags & COLFLAG_VIRTUAL );
|
||||
testcase( colFlags & COLFLAG_STORED );
|
||||
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);
|
||||
@ -2156,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;
|
||||
@ -2444,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;
|
||||
@ -3454,9 +3627,14 @@ void sqlite3CreateIndex(
|
||||
assert( j<=0x7fff );
|
||||
if( j<0 ){
|
||||
j = pTab->iPKey;
|
||||
}else if( pTab->aCol[j].notNull==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;
|
||||
}
|
||||
zColl = 0;
|
||||
@ -3510,13 +3688,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; j<pTab->nCol; j++){
|
||||
if( j==pTab->iPKey ) continue;
|
||||
if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue;
|
||||
if( sqlite3TableColumnToIndex(pIndex,j)>=0 ) continue;
|
||||
pIndex->isCovering = 0;
|
||||
break;
|
||||
}
|
||||
|
154
src/expr.c
154
src/expr.c
@ -3399,16 +3399,36 @@ 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.
|
||||
*/
|
||||
void sqlite3ExprCodeGetColumnOfTable(
|
||||
Vdbe *v, /* The VDBE under construction */
|
||||
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 */
|
||||
){
|
||||
Column *pCol;
|
||||
assert( v!=0 );
|
||||
if( pTab==0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
|
||||
return;
|
||||
@ -3416,14 +3436,36 @@ 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) ){
|
||||
x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol);
|
||||
int op;
|
||||
int x;
|
||||
if( IsVirtual(pTab) ){
|
||||
op = OP_VColumn;
|
||||
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{
|
||||
int savedSelfTab = pParse->iSelfTab;
|
||||
pCol->colFlags |= COLFLAG_BUSY;
|
||||
pParse->iSelfTab = iTabCur+1;
|
||||
sqlite3ExprCodeGeneratedColumn(pParse, pCol, regOut);
|
||||
pParse->iSelfTab = savedSelfTab;
|
||||
pCol->colFlags &= ~COLFLAG_BUSY;
|
||||
}
|
||||
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);
|
||||
}
|
||||
if( iCol>=0 ){
|
||||
sqlite3ColumnDefault(v, pTab, iCol, regOut);
|
||||
}
|
||||
}
|
||||
@ -3443,11 +3485,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->pVdbe, pTab, iTable, iColumn, iReg);
|
||||
if( p5 ){
|
||||
sqlite3VdbeChangeP5(v, p5);
|
||||
sqlite3VdbeChangeP5(pParse->pVdbe, p5);
|
||||
}
|
||||
return iReg;
|
||||
}
|
||||
@ -3583,19 +3624,46 @@ expr_code_doover:
|
||||
}
|
||||
if( iTab<0 ){
|
||||
if( pParse->iSelfTab<0 ){
|
||||
/* Generating CHECK constraints or inserting into partial index */
|
||||
assert( pExpr->y.pTab!=0 );
|
||||
assert( pExpr->iColumn>=XN_ROWID );
|
||||
assert( pExpr->iColumn<pExpr->y.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);
|
||||
/* 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;
|
||||
int iCol = pExpr->iColumn;
|
||||
assert( pTab!=0 );
|
||||
assert( iCol>=XN_ROWID );
|
||||
assert( iCol<pExpr->y.pTab->nCol );
|
||||
if( iCol<0 ){
|
||||
return -1-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 ){
|
||||
sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"",
|
||||
pCol->zName);
|
||||
return 0;
|
||||
}
|
||||
pCol->colFlags |= COLFLAG_BUSY;
|
||||
if( pCol->colFlags & COLFLAG_NOTAVAIL ){
|
||||
sqlite3ExprCodeGeneratedColumn(pParse, pCol, iSrc);
|
||||
}
|
||||
pCol->colFlags &= ~(COLFLAG_BUSY|COLFLAG_NOTAVAIL);
|
||||
return iSrc;
|
||||
}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
|
||||
@ -4063,17 +4131,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->iColumn<pTab->nCol );
|
||||
assert( pTab->iPKey<0 || pExpr->iColumn!=pTab->iPKey );
|
||||
assert( iCol>=-1 && iCol<pTab->nCol );
|
||||
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
|
||||
@ -4082,9 +4152,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
|
||||
@ -4317,15 +4385,11 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4354,30 +4418,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.
|
||||
@ -5300,7 +5340,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;
|
||||
|
16
src/fkey.c
16
src/fkey.c
@ -349,7 +349,7 @@ static void fkLookupParent(
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
for(i=0; i<pFKey->nCol; 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; i<nCol; i++){
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, aiCol[i]+1+regData, regTemp+i);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy,
|
||||
sqlite3TableColumnToStorage(pFKey->pFrom, 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; i<nCol; i++){
|
||||
int iChild = aiCol[i]+1+regData;
|
||||
int iParent = pIdx->aiColumn[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 ){
|
||||
|
352
src/insert.c
352
src/insert.c
@ -37,7 +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);
|
||||
sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol);
|
||||
VdbeComment((v, "%s", pTab->zName));
|
||||
}else{
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
@ -129,7 +129,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);
|
||||
@ -139,13 +139,15 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
|
||||
return;
|
||||
}
|
||||
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
for(i=j=0; i<pTab->nCol; 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 );
|
||||
@ -199,6 +201,61 @@ 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
|
||||
** 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 sqlite3ComputeGeneratedColumns(
|
||||
Parse *pParse, /* Parsing context */
|
||||
int iRegStore, /* Register holding the first column */
|
||||
Table *pTab /* The table */
|
||||
){
|
||||
int i;
|
||||
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; i<pTab->nCol; 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;
|
||||
}
|
||||
}
|
||||
/* 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=nv=0; i<pTab->nCol; i++){
|
||||
u32 colFlags = pTab->aCol[i].colFlags;
|
||||
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) );
|
||||
sqlite3ExprCodeGeneratedColumn(pParse, &pTab->aCol[i],
|
||||
iRegStore+pTab->nNVCol+nv);
|
||||
}else{
|
||||
/* Stored columns go in column order */
|
||||
assert( i-nv == sqlite3TableColumnToStorage(pTab,i) );
|
||||
sqlite3ExprCodeGeneratedColumn(pParse, &pTab->aCol[i], iRegStore+i-nv);
|
||||
}
|
||||
pTab->aCol[i].colFlags &= ~COLFLAG_NOTAVAIL;
|
||||
}
|
||||
if( (colFlags & COLFLAG_VIRTUAL)!=0 ) nv++;
|
||||
}
|
||||
pParse->iSelfTab = 0;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
/*
|
||||
** Locate or create an AutoincInfo structure associated with table pTab
|
||||
@ -506,7 +563,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 */
|
||||
){
|
||||
@ -531,6 +588,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 */
|
||||
@ -638,8 +696,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;
|
||||
@ -658,9 +716,17 @@ 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)==0;
|
||||
bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0;
|
||||
if( pColumn ){
|
||||
for(i=0; i<pColumn->nId; i++){
|
||||
pColumn->a[i].idx = -1;
|
||||
@ -673,6 +739,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;
|
||||
}
|
||||
}
|
||||
@ -782,13 +856,26 @@ void sqlite3Insert(
|
||||
*/
|
||||
if( pColumn==0 && nColumn>0 ){
|
||||
ipkColumn = pTab->iPKey;
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
if( ipkColumn>=0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){
|
||||
testcase( pTab->tabFlags & TF_HasVirtual );
|
||||
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_STORED );
|
||||
ipkColumn--;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Make sure the number of columns in the source data matches the number
|
||||
** of columns to be inserted into the table.
|
||||
*/
|
||||
for(i=0; i<pTab->nCol; 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,
|
||||
@ -873,7 +960,87 @@ 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; i<pTab->nCol; 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; j<pColumn->nId && 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
|
||||
*/
|
||||
@ -909,25 +1076,21 @@ void sqlite3Insert(
|
||||
*/
|
||||
assert( !IsVirtual(pTab) );
|
||||
|
||||
/* Create the new column data
|
||||
*/
|
||||
for(i=j=0; i<pTab->nCol; i++){
|
||||
if( pColumn ){
|
||||
for(j=0; j<pColumn->nId; 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_HasGenerated ){
|
||||
testcase( pTab->tabFlags & TF_HasVirtual );
|
||||
testcase( pTab->tabFlags & TF_HasStored );
|
||||
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.
|
||||
@ -945,19 +1108,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) ){
|
||||
@ -990,45 +1151,17 @@ void sqlite3Insert(
|
||||
}
|
||||
autoIncStep(pParse, regAutoinc, regRowid);
|
||||
|
||||
/* Compute data for all columns of the new entry, beginning
|
||||
** with the first column.
|
||||
*/
|
||||
nHidden = 0;
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
int iRegStore = regRowid+1+i;
|
||||
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( pColumn==0 ){
|
||||
if( IsHiddenColumn(&pTab->aCol[i]) ){
|
||||
j = -1;
|
||||
nHidden++;
|
||||
}else{
|
||||
j = i - nHidden;
|
||||
}
|
||||
}else{
|
||||
for(j=0; j<pColumn->nId; j++){
|
||||
if( pColumn->a[j].idx==i ) break;
|
||||
}
|
||||
}
|
||||
if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){
|
||||
sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
|
||||
}else if( useTempTable ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore);
|
||||
}else if( pSelect ){
|
||||
if( regFromSelect!=regData ){
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore);
|
||||
}
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore);
|
||||
}
|
||||
#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_HasGenerated ){
|
||||
testcase( pTab->tabFlags & TF_HasVirtual );
|
||||
testcase( pTab->tabFlags & TF_HasStored );
|
||||
sqlite3ComputeGeneratedColumns(pParse, regRowid+1, pTab);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate code to check constraints and generate index keys and
|
||||
** do the insertion.
|
||||
@ -1354,9 +1487,9 @@ void sqlite3GenerateConstraintChecks(
|
||||
*/
|
||||
if( pTab->tabFlags & TF_HasNotNull ){
|
||||
for(i=0; i<nCol; i++){
|
||||
int iReg;
|
||||
onError = pTab->aCol[i].notNull;
|
||||
if( onError==OE_None ) continue; /* No NOT NULL on this column */
|
||||
assert( pTab->tabFlags & TF_HasNotNull );
|
||||
if( i==pTab->iPKey ){
|
||||
continue; /* ROWID is never NULL */
|
||||
}
|
||||
@ -1364,6 +1497,8 @@ void sqlite3GenerateConstraintChecks(
|
||||
/* Don't bother checking for NOT NULL on columns that do not change */
|
||||
continue;
|
||||
}
|
||||
onError = pTab->aCol[i].notNull;
|
||||
if( onError==OE_None ) continue; /* This column is allowed to be NULL */
|
||||
if( overrideError!=OE_Default ){
|
||||
onError = overrideError;
|
||||
}else if( onError==OE_Default ){
|
||||
@ -1375,14 +1510,18 @@ void sqlite3GenerateConstraintChecks(
|
||||
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|
||||
|| onError==OE_Ignore || onError==OE_Replace );
|
||||
addr1 = 0;
|
||||
testcase( i!=sqlite3TableColumnToStorage(pTab, i) );
|
||||
testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL );
|
||||
testcase( pTab->aCol[i].colFlags & COLFLAG_STORED );
|
||||
iReg = sqlite3TableColumnToStorage(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
|
||||
@ -1396,7 +1535,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);
|
||||
onError, iReg);
|
||||
sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
|
||||
sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
|
||||
VdbeCoverage(v);
|
||||
@ -1405,7 +1544,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;
|
||||
}
|
||||
@ -1721,14 +1860,22 @@ 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 ){
|
||||
}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{
|
||||
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));
|
||||
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));
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
|
||||
@ -1818,7 +1965,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
if( pIdx!=pPk ){
|
||||
for(i=0; i<pPk->nKeyCol; 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));
|
||||
@ -1982,7 +2129,7 @@ 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->nNVCol, regRec);
|
||||
sqlite3SetMakeRecordP5(v, pTab);
|
||||
if( !bAffinityDone ){
|
||||
sqlite3TableAffinity(v, pTab, 0);
|
||||
@ -2376,6 +2523,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-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 */
|
||||
@ -2387,7 +2567,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)
|
||||
|
@ -347,6 +347,10 @@ 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}
|
||||
|
19
src/pragma.c
19
src/pragma.c
@ -1100,11 +1100,20 @@ void sqlite3Pragma(
|
||||
sqlite3CodeVerifySchema(pParse, iTabDb);
|
||||
sqlite3ViewGetColumnNames(pParse, pTab);
|
||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||
int isHidden = IsHiddenColumn(pCol);
|
||||
if( isHidden && pPragma->iArg==0 ){
|
||||
int isHidden = 0;
|
||||
if( pCol->colFlags & COLFLAG_NOINSERT ){
|
||||
if( pPragma->iArg==0 ){
|
||||
nHidden++;
|
||||
continue;
|
||||
}
|
||||
if( pCol->colFlags & COLFLAG_VIRTUAL ){
|
||||
isHidden = 2; /* GENERATED ALWAYS AS ... VIRTUAL */
|
||||
}else if( pCol->colFlags & COLFLAG_STORED ){
|
||||
isHidden = 3; /* GENERATED ALWAYS AS ... STORED */
|
||||
}else{ assert( pCol->colFlags & COLFLAG_HIDDEN );
|
||||
isHidden = 1; /* HIDDEN */
|
||||
}
|
||||
}
|
||||
if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){
|
||||
k = 0;
|
||||
}else if( pPk==0 ){
|
||||
@ -1112,13 +1121,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);
|
||||
}
|
||||
@ -1577,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-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 */
|
||||
|
@ -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 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
|
||||
@ -1798,7 +1804,7 @@ void sqlite3ResolveSelectNames(
|
||||
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 */
|
||||
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. */
|
||||
){
|
||||
@ -1807,7 +1813,8 @@ int sqlite3ResolveSelfReference(
|
||||
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 ){
|
||||
|
@ -1818,17 +1818,30 @@ 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 */
|
||||
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 */
|
||||
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:
|
||||
@ -1838,6 +1851,12 @@ struct Column {
|
||||
#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 */
|
||||
#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 */
|
||||
|
||||
/*
|
||||
** A "Collating Sequence" is defined by an instance of the following
|
||||
@ -1977,6 +1996,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 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
|
||||
@ -2003,20 +2023,28 @@ 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_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 */
|
||||
#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
|
||||
@ -2267,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 */
|
||||
@ -2808,21 +2837,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_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
|
||||
@ -3937,7 +3967,14 @@ 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 sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */
|
||||
# define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */
|
||||
#else
|
||||
i16 sqlite3TableColumnToStorage(Table*, i16);
|
||||
i16 sqlite3StorageColumnToTable(Table*, i16);
|
||||
#endif
|
||||
void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
|
||||
#if SQLITE_ENABLE_HIDDEN_COLUMNS
|
||||
void sqlite3ColumnPropertiesFromName(Table*, Column*);
|
||||
@ -3950,6 +3987,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 **);
|
||||
@ -4007,6 +4045,9 @@ void sqlite3FreeIndex(sqlite3*, Index*);
|
||||
# define sqlite3AutoincrementEnd(X)
|
||||
#endif
|
||||
void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*);
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
void sqlite3ComputeGeneratedColumns(Parse*, int, Table*);
|
||||
#endif
|
||||
void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
|
||||
IdList *sqlite3IdListAppend(Parse*, IdList*, Token*);
|
||||
int sqlite3IdListIndex(IdList*,const char*);
|
||||
@ -4056,12 +4097,14 @@ 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);
|
||||
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 */
|
||||
|
90
src/update.c
90
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 */
|
||||
@ -312,6 +312,16 @@ 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_GENERATED ){
|
||||
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);
|
||||
goto update_cleanup;
|
||||
}
|
||||
#endif
|
||||
aXRef[j] = i;
|
||||
break;
|
||||
}
|
||||
@ -346,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; i<pTab->nCol; 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
|
||||
@ -543,7 +580,8 @@ void sqlite3Update(
|
||||
** is not required) and leave the PK fields in the array of registers. */
|
||||
for(i=0; i<nPk; i++){
|
||||
assert( pPk->aiColumn[i]>=0 );
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,pPk->aiColumn[i],iPk+i);
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,
|
||||
pPk->aiColumn[i], iPk+i);
|
||||
}
|
||||
if( eOnePass ){
|
||||
if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen);
|
||||
@ -623,15 +661,20 @@ void sqlite3Update(
|
||||
oldmask |= sqlite3TriggerColmask(pParse,
|
||||
pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError
|
||||
);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
for(i=0, k=regOld; i<pTab->nCol; 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(v, pTab, iDataCur, i, regOld+i);
|
||||
sqlite3ExprCodeGetColumnOfTable(v, 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 +698,15 @@ void sqlite3Update(
|
||||
newmask = sqlite3TriggerColmask(
|
||||
pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
|
||||
);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
for(i=0, k=regNew; i<pTab->nCol; 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_GENERATED)!=0 ){
|
||||
if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) 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,12 +715,19 @@ void sqlite3Update(
|
||||
*/
|
||||
testcase( i==31 );
|
||||
testcase( i==32 );
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
if( pTab->tabFlags & TF_HasGenerated ){
|
||||
testcase( pTab->tabFlags & TF_HasVirtual );
|
||||
testcase( pTab->tabFlags & TF_HasStored );
|
||||
sqlite3ComputeGeneratedColumns(pParse, regNew, pTab);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fire any BEFORE UPDATE triggers. This happens before constraints are
|
||||
** verified. One could argue that this is wrong.
|
||||
@ -708,11 +760,20 @@ void sqlite3Update(
|
||||
** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26)
|
||||
** for an example.
|
||||
*/
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( aXRef[i]<0 && i!=pTab->iPKey ){
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
|
||||
for(i=0, k=regNew; i<pTab->nCol; i++, 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(v, pTab, iDataCur, i, k);
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
if( pTab->tabFlags & TF_HasGenerated ){
|
||||
testcase( pTab->tabFlags & TF_HasVirtual );
|
||||
testcase( pTab->tabFlags & TF_HasStored );
|
||||
sqlite3ComputeGeneratedColumns(pParse, regNew, pTab);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if( !isView ){
|
||||
@ -918,6 +979,7 @@ static void updateVirtualTable(
|
||||
|
||||
/* Populate the argument registers. */
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 );
|
||||
if( aXRef[i]>=0 ){
|
||||
sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
|
||||
}else{
|
||||
|
@ -226,7 +226,7 @@ void sqlite3UpsertDoUpdate(
|
||||
for(i=0; i<nPk; i++){
|
||||
int k;
|
||||
assert( pPk->aiColumn[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));
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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".
|
||||
|
@ -5376,8 +5376,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
x = pPk->aiColumn[x];
|
||||
assert( x>=0 );
|
||||
}else{
|
||||
testcase( x!=sqlite3StorageColumnToTable(pTab,x) );
|
||||
x = sqlite3StorageColumnToTable(pTab,x);
|
||||
}
|
||||
x = sqlite3ColumnOfIndex(pIdx, x);
|
||||
x = sqlite3TableColumnToIndex(pIdx, x);
|
||||
if( x>=0 ){
|
||||
pOp->p2 = x;
|
||||
pOp->p1 = pLevel->iIdxCur;
|
||||
|
@ -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 ){
|
||||
@ -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,31 @@ 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;
|
||||
pExpr->y.pTab = 0;
|
||||
}
|
||||
}
|
||||
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 +1163,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; iIdxCol<aColExpr->nExpr; iIdxCol++){
|
||||
if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue;
|
||||
for(iIdxCol=0; iIdxCol<pIdx->nColumn; iIdxCol++){
|
||||
i16 iRef = pIdx->aiColumn[iIdxCol];
|
||||
if( iRef==XN_EXPR ){
|
||||
assert( aColExpr->a[iIdxCol].pExpr!=0 );
|
||||
x.iIdxCol = iIdxCol;
|
||||
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;
|
||||
sqlite3WalkExpr(&w, pWInfo->pWhere);
|
||||
sqlite3WalkExprList(&w, pWInfo->pOrderBy);
|
||||
sqlite3WalkExprList(&w, pWInfo->pResultSet);
|
||||
@ -1826,7 +1863,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
|
||||
iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
||||
for(j=0; j<pPk->nKeyCol; 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,
|
||||
@ -1835,7 +1872,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
|
||||
@ -2086,7 +2125,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
r = sqlite3GetTempRange(pParse, nPk);
|
||||
for(iPk=0; iPk<nPk; iPk++){
|
||||
int iCol = pPk->aiColumn[iPk];
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, r+iPk);
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk);
|
||||
}
|
||||
|
||||
/* Check if the temp table already contains this key. If so,
|
||||
|
@ -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 },
|
||||
|
Loading…
x
Reference in New Issue
Block a user