From 2bc2286f67734862357603774cb3dcf09dfb82f4 Mon Sep 17 00:00:00 2001 From: Kirill Yukhin <kirill.yukhin@gmail.com> Date: Fri, 21 Jul 2017 17:23:16 +0300 Subject: [PATCH] sql: Support per-statement transactions Introduce dedicated opcode OP_TTRansaction, which is responsible for initiation of Tarantool transaction. This opcode is only emitted if statement is generated directly by parser. That means that changes like insertions into system tables are not covered by Tarantool's transations. Tarantool's transaction is committed or rolled back during exectuin of `Halt` opcode. `CloseAllCursors` function was splitted into two: in order Tarantool's WAL to work need to preserve allocated memory until commit to WAL. Call this deallocation after Tarantool's commit. In future this will be re-worked since transaction can be either in statement or generic, and not all Halts should commit. Also, fix a bug: memory area passed to WAL were re-used. WAL itself doesn't do memcpy, so this state of affairs was lead to unpredictable errors during save/restore. Use region_alloc to reserve memory area for WAL in tarantoolSqlite3Insert and tarantoolSqlite3Delete. Closes #2599 --- src/box/sql.c | 18 +- src/box/sql/build.c | 3 + src/box/sql/delete.c | 5 + src/box/sql/opcodes.c | 127 +++--- src/box/sql/opcodes.h | 143 +++---- src/box/sql/parse.c | 450 +++++++++++---------- src/box/sql/parse.y | 12 + src/box/sql/sqliteInt.h | 4 + src/box/sql/trigger.c | 15 +- src/box/sql/vdbe.c | 15 + src/box/sql/vdbeaux.c | 40 +- test/sql-tap/gh2259-in-stmt-trans.test.lua | 84 ++++ test/sql/persistency.result | 36 ++ test/sql/persistency.test.lua | 7 + 14 files changed, 584 insertions(+), 375 deletions(-) create mode 100755 test/sql-tap/gh2259-in-stmt-trans.test.lua diff --git a/src/box/sql.c b/src/box/sql.c index 080f2f8a23..f1bb1f019d 100644 --- a/src/box/sql.c +++ b/src/box/sql.c @@ -322,8 +322,15 @@ int tarantoolSqlite3Insert(BtCursor *pCur, const BtreePayload *pX) { assert(pCur->curFlags & BTCF_TaCursor); + char *buf = (char*)region_alloc(&fiber()->gc, pX->nKey); + if (buf == NULL) { + diag_set(OutOfMemory, pX->nKey, "malloc", "buf"); + return SQLITE_TARANTOOL_ERROR; + } + + memcpy(buf, pX->pKey, pX->nKey); if (box_replace(SQLITE_PAGENO_TO_SPACEID(pCur->pgnoRoot), - pX->pKey, (const char *)pX->pKey + pX->nKey, + buf, (const char *)buf + pX->nKey, NULL) != 0) { return SQLITE_TARANTOOL_ERROR; @@ -339,8 +346,7 @@ int tarantoolSqlite3Delete(BtCursor *pCur, u8 flags) struct ta_cursor *c = pCur->pTaCursor; uint32_t space_id, index_id; - size_t original_size; - const char *key; + char *key; uint32_t key_size; int rc; @@ -350,14 +356,14 @@ int tarantoolSqlite3Delete(BtCursor *pCur, u8 flags) space_id = SQLITE_PAGENO_TO_SPACEID(pCur->pgnoRoot); index_id = SQLITE_PAGENO_TO_INDEXID(pCur->pgnoRoot); - original_size = region_used(&fiber()->gc); key = tuple_extract_key(c->tuple_last, box_iterator_key_def(c->iter), &key_size); if (key == NULL) return SQLITE_TARANTOOL_ERROR; - rc = box_delete(space_id, index_id, key, key+key_size, NULL); - region_truncate(&fiber()->gc, original_size); + + rc = box_delete(space_id, index_id, key, key + key_size, NULL); + return rc == 0 ? SQLITE_OK : SQLITE_TARANTOOL_ERROR; } diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 91689f04ff..72422cf325 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -188,6 +188,9 @@ void sqlite3FinishCoding(Parse *pParse){ pSchema->schema_cookie, /* P3 */ pSchema->iGeneration /* P4 */ ); + if (pParse->initiateTTrans) + sqlite3VdbeAddOp0(v, OP_TTransaction); + if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1); VdbeComment((v, "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite)); diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c index d9ec6bd584..491414772e 100644 --- a/src/box/sql/delete.c +++ b/src/box/sql/delete.c @@ -369,6 +369,11 @@ void sqlite3DeleteFrom( assert( pIdx->pSchema==pTab->pSchema ); sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb); } + + /* Do not start Tarantool's transaction in case of truncate optimization. + This is workaround until system tables cannot be changes inside a + transaction (_truncate). */ + pParse->initiateTTrans = false; }else #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */ { diff --git a/src/box/sql/opcodes.c b/src/box/sql/opcodes.c index 50cbbfe517..780bde8099 100644 --- a/src/box/sql/opcodes.c +++ b/src/box/sql/opcodes.c @@ -112,70 +112,71 @@ const char *sqlite3OpcodeName(int i){ /* 98 */ "Affinity" OpHelp("affinity(r[P1@P2])"), /* 99 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), /* 100 */ "Count" OpHelp("r[P2]=count()"), - /* 101 */ "ReadCookie" OpHelp(""), - /* 102 */ "SetCookie" OpHelp(""), - /* 103 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), - /* 104 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 105 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), - /* 106 */ "OpenAutoindex" OpHelp("nColumn=P2"), - /* 107 */ "OpenEphemeral" OpHelp("nColumn=P2"), - /* 108 */ "SorterOpen" OpHelp(""), - /* 109 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), - /* 110 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), - /* 111 */ "Close" OpHelp(""), - /* 112 */ "ColumnsUsed" OpHelp(""), - /* 113 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), - /* 114 */ "NewRowid" OpHelp("r[P2]=rowid"), - /* 115 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), - /* 116 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), - /* 117 */ "Delete" OpHelp(""), - /* 118 */ "ResetCount" OpHelp(""), - /* 119 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), - /* 120 */ "SorterData" OpHelp("r[P2]=data"), - /* 121 */ "RowData" OpHelp("r[P2]=data"), - /* 122 */ "Rowid" OpHelp("r[P2]=rowid"), - /* 123 */ "NullRow" OpHelp(""), - /* 124 */ "SorterInsert" OpHelp("key=r[P2]"), - /* 125 */ "IdxInsert" OpHelp("key=r[P2]"), - /* 126 */ "IdxDelete" OpHelp("key=r[P2@P3]"), - /* 127 */ "Seek" OpHelp("Move P3 to P1.rowid"), - /* 128 */ "IdxRowid" OpHelp("r[P2]=rowid"), - /* 129 */ "Destroy" OpHelp(""), - /* 130 */ "Clear" OpHelp(""), - /* 131 */ "ResetSorter" OpHelp(""), + /* 101 */ "TTransaction" OpHelp(""), + /* 102 */ "ReadCookie" OpHelp(""), + /* 103 */ "SetCookie" OpHelp(""), + /* 104 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), + /* 105 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 106 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 107 */ "OpenAutoindex" OpHelp("nColumn=P2"), + /* 108 */ "OpenEphemeral" OpHelp("nColumn=P2"), + /* 109 */ "SorterOpen" OpHelp(""), + /* 110 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"), + /* 111 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 112 */ "Close" OpHelp(""), + /* 113 */ "ColumnsUsed" OpHelp(""), + /* 114 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), + /* 115 */ "NewRowid" OpHelp("r[P2]=rowid"), + /* 116 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"), + /* 117 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"), + /* 118 */ "Delete" OpHelp(""), + /* 119 */ "ResetCount" OpHelp(""), + /* 120 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), + /* 121 */ "SorterData" OpHelp("r[P2]=data"), + /* 122 */ "RowData" OpHelp("r[P2]=data"), + /* 123 */ "Rowid" OpHelp("r[P2]=rowid"), + /* 124 */ "NullRow" OpHelp(""), + /* 125 */ "SorterInsert" OpHelp("key=r[P2]"), + /* 126 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 127 */ "IdxDelete" OpHelp("key=r[P2@P3]"), + /* 128 */ "Seek" OpHelp("Move P3 to P1.rowid"), + /* 129 */ "IdxRowid" OpHelp("r[P2]=rowid"), + /* 130 */ "Destroy" OpHelp(""), + /* 131 */ "Clear" OpHelp(""), /* 132 */ "Real" OpHelp("r[P2]=P4"), - /* 133 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"), - /* 134 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"), - /* 135 */ "ParseSchema" OpHelp(""), - /* 136 */ "ParseSchema2" OpHelp("rows=r[P1@P2] iDb=P3"), - /* 137 */ "ParseSchema3" OpHelp("name=r[P1] sql=r[P1+1] iDb=P2"), - /* 138 */ "LoadAnalysis" OpHelp(""), - /* 139 */ "DropTable" OpHelp(""), - /* 140 */ "DropIndex" OpHelp(""), - /* 141 */ "DropTrigger" OpHelp(""), - /* 142 */ "IntegrityCk" OpHelp(""), - /* 143 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), - /* 144 */ "Param" OpHelp(""), - /* 145 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), - /* 146 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), - /* 147 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), - /* 148 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 149 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 150 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 151 */ "Expire" OpHelp(""), - /* 152 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 153 */ "VBegin" OpHelp(""), - /* 154 */ "VCreate" OpHelp(""), - /* 155 */ "VDestroy" OpHelp(""), - /* 156 */ "VOpen" OpHelp(""), - /* 157 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 158 */ "VRename" OpHelp(""), - /* 159 */ "Pagecount" OpHelp(""), - /* 160 */ "MaxPgcnt" OpHelp(""), - /* 161 */ "CursorHint" OpHelp(""), - /* 162 */ "IncMaxid" OpHelp(""), - /* 163 */ "Noop" OpHelp(""), - /* 164 */ "Explain" OpHelp(""), + /* 133 */ "ResetSorter" OpHelp(""), + /* 134 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"), + /* 135 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"), + /* 136 */ "ParseSchema" OpHelp(""), + /* 137 */ "ParseSchema2" OpHelp("rows=r[P1@P2] iDb=P3"), + /* 138 */ "ParseSchema3" OpHelp("name=r[P1] sql=r[P1+1] iDb=P2"), + /* 139 */ "LoadAnalysis" OpHelp(""), + /* 140 */ "DropTable" OpHelp(""), + /* 141 */ "DropIndex" OpHelp(""), + /* 142 */ "DropTrigger" OpHelp(""), + /* 143 */ "IntegrityCk" OpHelp(""), + /* 144 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 145 */ "Param" OpHelp(""), + /* 146 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 147 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 148 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 149 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 150 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 151 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 152 */ "Expire" OpHelp(""), + /* 153 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 154 */ "VBegin" OpHelp(""), + /* 155 */ "VCreate" OpHelp(""), + /* 156 */ "VDestroy" OpHelp(""), + /* 157 */ "VOpen" OpHelp(""), + /* 158 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 159 */ "VRename" OpHelp(""), + /* 160 */ "Pagecount" OpHelp(""), + /* 161 */ "MaxPgcnt" OpHelp(""), + /* 162 */ "CursorHint" OpHelp(""), + /* 163 */ "IncMaxid" OpHelp(""), + /* 164 */ "Noop" OpHelp(""), + /* 165 */ "Explain" OpHelp(""), }; return azName[i]; } diff --git a/src/box/sql/opcodes.h b/src/box/sql/opcodes.h index bba957ea4e..cb1af3bf58 100644 --- a/src/box/sql/opcodes.h +++ b/src/box/sql/opcodes.h @@ -101,70 +101,71 @@ #define OP_Affinity 98 /* synopsis: affinity(r[P1@P2]) */ #define OP_MakeRecord 99 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ #define OP_Count 100 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 101 -#define OP_SetCookie 102 -#define OP_ReopenIdx 103 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenRead 104 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenWrite 105 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenAutoindex 106 /* synopsis: nColumn=P2 */ -#define OP_OpenEphemeral 107 /* synopsis: nColumn=P2 */ -#define OP_SorterOpen 108 -#define OP_SequenceTest 109 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ -#define OP_OpenPseudo 110 /* synopsis: P3 columns in r[P2] */ -#define OP_Close 111 -#define OP_ColumnsUsed 112 -#define OP_Sequence 113 /* synopsis: r[P2]=cursor[P1].ctr++ */ -#define OP_NewRowid 114 /* synopsis: r[P2]=rowid */ -#define OP_Insert 115 /* synopsis: intkey=r[P3] data=r[P2] */ -#define OP_InsertInt 116 /* synopsis: intkey=P3 data=r[P2] */ -#define OP_Delete 117 -#define OP_ResetCount 118 -#define OP_SorterCompare 119 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ -#define OP_SorterData 120 /* synopsis: r[P2]=data */ -#define OP_RowData 121 /* synopsis: r[P2]=data */ -#define OP_Rowid 122 /* synopsis: r[P2]=rowid */ -#define OP_NullRow 123 -#define OP_SorterInsert 124 /* synopsis: key=r[P2] */ -#define OP_IdxInsert 125 /* synopsis: key=r[P2] */ -#define OP_IdxDelete 126 /* synopsis: key=r[P2@P3] */ -#define OP_Seek 127 /* synopsis: Move P3 to P1.rowid */ -#define OP_IdxRowid 128 /* synopsis: r[P2]=rowid */ -#define OP_Destroy 129 -#define OP_Clear 130 -#define OP_ResetSorter 131 +#define OP_TTransaction 101 +#define OP_ReadCookie 102 +#define OP_SetCookie 103 +#define OP_ReopenIdx 104 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenRead 105 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 106 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenAutoindex 107 /* synopsis: nColumn=P2 */ +#define OP_OpenEphemeral 108 /* synopsis: nColumn=P2 */ +#define OP_SorterOpen 109 +#define OP_SequenceTest 110 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */ +#define OP_OpenPseudo 111 /* synopsis: P3 columns in r[P2] */ +#define OP_Close 112 +#define OP_ColumnsUsed 113 +#define OP_Sequence 114 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NewRowid 115 /* synopsis: r[P2]=rowid */ +#define OP_Insert 116 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_InsertInt 117 /* synopsis: intkey=P3 data=r[P2] */ +#define OP_Delete 118 +#define OP_ResetCount 119 +#define OP_SorterCompare 120 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ +#define OP_SorterData 121 /* synopsis: r[P2]=data */ +#define OP_RowData 122 /* synopsis: r[P2]=data */ +#define OP_Rowid 123 /* synopsis: r[P2]=rowid */ +#define OP_NullRow 124 +#define OP_SorterInsert 125 /* synopsis: key=r[P2] */ +#define OP_IdxInsert 126 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 127 /* synopsis: key=r[P2@P3] */ +#define OP_Seek 128 /* synopsis: Move P3 to P1.rowid */ +#define OP_IdxRowid 129 /* synopsis: r[P2]=rowid */ +#define OP_Destroy 130 +#define OP_Clear 131 #define OP_Real 132 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_CreateIndex 133 /* synopsis: r[P2]=root iDb=P1 */ -#define OP_CreateTable 134 /* synopsis: r[P2]=root iDb=P1 */ -#define OP_ParseSchema 135 -#define OP_ParseSchema2 136 /* synopsis: rows=r[P1@P2] iDb=P3 */ -#define OP_ParseSchema3 137 /* synopsis: name=r[P1] sql=r[P1+1] iDb=P2 */ -#define OP_LoadAnalysis 138 -#define OP_DropTable 139 -#define OP_DropIndex 140 -#define OP_DropTrigger 141 -#define OP_IntegrityCk 142 -#define OP_RowSetAdd 143 /* synopsis: rowset(P1)=r[P2] */ -#define OP_Param 144 -#define OP_FkCounter 145 /* synopsis: fkctr[P1]+=P2 */ -#define OP_MemMax 146 /* synopsis: r[P1]=max(r[P1],r[P2]) */ -#define OP_OffsetLimit 147 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ -#define OP_AggStep0 148 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggStep 149 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggFinal 150 /* synopsis: accum=r[P1] N=P2 */ -#define OP_Expire 151 -#define OP_TableLock 152 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 153 -#define OP_VCreate 154 -#define OP_VDestroy 155 -#define OP_VOpen 156 -#define OP_VColumn 157 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VRename 158 -#define OP_Pagecount 159 -#define OP_MaxPgcnt 160 -#define OP_CursorHint 161 -#define OP_IncMaxid 162 -#define OP_Noop 163 -#define OP_Explain 164 +#define OP_ResetSorter 133 +#define OP_CreateIndex 134 /* synopsis: r[P2]=root iDb=P1 */ +#define OP_CreateTable 135 /* synopsis: r[P2]=root iDb=P1 */ +#define OP_ParseSchema 136 +#define OP_ParseSchema2 137 /* synopsis: rows=r[P1@P2] iDb=P3 */ +#define OP_ParseSchema3 138 /* synopsis: name=r[P1] sql=r[P1+1] iDb=P2 */ +#define OP_LoadAnalysis 139 +#define OP_DropTable 140 +#define OP_DropIndex 141 +#define OP_DropTrigger 142 +#define OP_IntegrityCk 143 +#define OP_RowSetAdd 144 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 145 +#define OP_FkCounter 146 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 147 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 148 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggStep0 149 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep 150 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggFinal 151 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 152 +#define OP_TableLock 153 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 154 +#define OP_VCreate 155 +#define OP_VDestroy 156 +#define OP_VOpen 157 +#define OP_VColumn 158 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 159 +#define OP_Pagecount 160 +#define OP_MaxPgcnt 161 +#define OP_CursorHint 162 +#define OP_IncMaxid 163 +#define OP_Noop 164 +#define OP_Explain 165 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c @@ -189,15 +190,15 @@ /* 72 */ 0x02, 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10,\ /* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00,\ /* 88 */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,\ -/* 96 */ 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ +/* 96 */ 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00,\ /* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 112 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 120 */ 0x00, 0x00, 0x10, 0x00, 0x04, 0x04, 0x00, 0x00,\ -/* 128 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00,\ -/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,\ -/* 144 */ 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00,\ -/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\ -/* 160 */ 0x10, 0x00, 0x00, 0x00, 0x00,} +/* 112 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,\ +/* 120 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x04, 0x00,\ +/* 128 */ 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10,\ +/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 144 */ 0x06, 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00,\ +/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 160 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,} /* The sqlite3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum diff --git a/src/box/sql/parse.c b/src/box/sql/parse.c index 4f3e788596..5b16f1bcc3 100644 --- a/src/box/sql/parse.c +++ b/src/box/sql/parse.c @@ -103,7 +103,7 @@ static void disableLookaside(Parse *pParse){ } } } -#line 831 "parse.y" +#line 843 "parse.y" /* This is a utility routine used to set the ExprSpan.zStart and ** ExprSpan.zEnd values of pOut so that the span covers the complete @@ -140,7 +140,7 @@ static void disableLookaside(Parse *pParse){ pOut->zStart = t.z; pOut->zEnd = &t.z[t.n]; } -#line 948 "parse.y" +#line 960 "parse.y" /* This routine constructs a binary expression node out of two ExprSpan ** objects and uses the result to populate a new ExprSpan object. @@ -163,7 +163,7 @@ static void disableLookaside(Parse *pParse){ pSpan->pExpr = sqlite3PExpr(pParse, TK_NOT, pSpan->pExpr, 0); } } -#line 1022 "parse.y" +#line 1034 "parse.y" /* Construct an expression node for a unary postfix operator */ @@ -176,7 +176,7 @@ static void disableLookaside(Parse *pParse){ pOperand->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0); pOperand->zEnd = &pPostOp->z[pPostOp->n]; } -#line 1039 "parse.y" +#line 1051 "parse.y" /* A routine to convert a binary TK_IS or TK_ISNOT expression into a ** unary TK_ISNULL or TK_NOTNULL expression. */ @@ -188,7 +188,7 @@ static void disableLookaside(Parse *pParse){ pA->pRight = 0; } } -#line 1067 "parse.y" +#line 1079 "parse.y" /* Construct an expression node for a unary prefix operator */ @@ -203,7 +203,7 @@ static void disableLookaside(Parse *pParse){ pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0); pOut->zEnd = pOperand->zEnd; } -#line 1279 "parse.y" +#line 1291 "parse.y" /* Add a single new term to an ExprList that is used to store a ** list of identifiers. Report an error if the ID list contains @@ -1571,7 +1571,7 @@ sqlite3SelectDelete(pParse->db, (yypminor->yy159)); case 171: /* term */ case 172: /* expr */ { -#line 829 "parse.y" +#line 841 "parse.y" sqlite3ExprDelete(pParse->db, (yypminor->yy342).pExpr); #line 1577 "parse.c" } @@ -1589,7 +1589,7 @@ sqlite3ExprDelete(pParse->db, (yypminor->yy342).pExpr); case 223: /* paren_exprlist */ case 225: /* case_exprlist */ { -#line 1277 "parse.y" +#line 1289 "parse.y" sqlite3ExprListDelete(pParse->db, (yypminor->yy442)); #line 1595 "parse.c" } @@ -1607,7 +1607,7 @@ sqlite3SrcListDelete(pParse->db, (yypminor->yy347)); case 195: /* with */ case 249: /* wqlist */ { -#line 1554 "parse.y" +#line 1566 "parse.y" sqlite3WithDelete(pParse->db, (yypminor->yy331)); #line 1613 "parse.c" } @@ -1620,7 +1620,7 @@ sqlite3WithDelete(pParse->db, (yypminor->yy331)); case 235: /* when_clause */ case 240: /* key_opt */ { -#line 746 "parse.y" +#line 750 "parse.y" sqlite3ExprDelete(pParse->db, (yypminor->yy122)); #line 1626 "parse.c" } @@ -1637,14 +1637,14 @@ sqlite3IdListDelete(pParse->db, (yypminor->yy180)); case 231: /* trigger_cmd_list */ case 236: /* trigger_cmd */ { -#line 1391 "parse.y" +#line 1403 "parse.y" sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy327)); #line 1643 "parse.c" } break; case 233: /* trigger_event */ { -#line 1377 "parse.y" +#line 1389 "parse.y" sqlite3IdListDelete(pParse->db, (yypminor->yy410).b); #line 1650 "parse.c" } @@ -3048,120 +3048,128 @@ static void yy_reduce( #line 3049 "parse.c" break; case 135: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */ -#line 737 "parse.y" +#line 739 "parse.y" { sqlite3WithPush(pParse, yymsp[-5].minor.yy331, 1); sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy347, &yymsp[-1].minor.yy0); sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS; + /* Instruct SQL to initate Tarantool's transaction. */ + pParse->initiateTTrans = true; sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy347,yymsp[0].minor.yy122); } -#line 3059 "parse.c" +#line 3061 "parse.c" break; case 138: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */ -#line 766 "parse.y" +#line 772 "parse.y" { sqlite3WithPush(pParse, yymsp[-7].minor.yy331, 1); sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy347, &yymsp[-3].minor.yy0); sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy442,"set list"); sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS; + /* Instruct SQL to initate Tarantool's transaction. */ + pParse->initiateTTrans = true; sqlite3Update(pParse,yymsp[-4].minor.yy347,yymsp[-1].minor.yy442,yymsp[0].minor.yy122,yymsp[-5].minor.yy392); } -#line 3070 "parse.c" +#line 3074 "parse.c" break; case 139: /* setlist ::= setlist COMMA nm EQ expr */ -#line 778 "parse.y" +#line 786 "parse.y" { yymsp[-4].minor.yy442 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy442, yymsp[0].minor.yy342.pExpr); sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy442, &yymsp[-2].minor.yy0, 1); } -#line 3078 "parse.c" +#line 3082 "parse.c" break; case 140: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ -#line 782 "parse.y" +#line 790 "parse.y" { yymsp[-6].minor.yy442 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy442, yymsp[-3].minor.yy180, yymsp[0].minor.yy342.pExpr); } -#line 3085 "parse.c" +#line 3089 "parse.c" break; case 141: /* setlist ::= nm EQ expr */ -#line 785 "parse.y" +#line 793 "parse.y" { yylhsminor.yy442 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy342.pExpr); sqlite3ExprListSetName(pParse, yylhsminor.yy442, &yymsp[-2].minor.yy0, 1); } -#line 3093 "parse.c" +#line 3097 "parse.c" yymsp[-2].minor.yy442 = yylhsminor.yy442; break; case 142: /* setlist ::= LP idlist RP EQ expr */ -#line 789 "parse.y" +#line 797 "parse.y" { yymsp[-4].minor.yy442 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy180, yymsp[0].minor.yy342.pExpr); } -#line 3101 "parse.c" +#line 3105 "parse.c" break; case 143: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */ -#line 795 "parse.y" +#line 803 "parse.y" { sqlite3WithPush(pParse, yymsp[-5].minor.yy331, 1); sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS; + /* Instruct SQL to initate Tarantool's transaction. */ + pParse->initiateTTrans = true; sqlite3Insert(pParse, yymsp[-2].minor.yy347, yymsp[0].minor.yy159, yymsp[-1].minor.yy180, yymsp[-4].minor.yy392); } -#line 3110 "parse.c" +#line 3116 "parse.c" break; case 144: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */ -#line 801 "parse.y" +#line 811 "parse.y" { sqlite3WithPush(pParse, yymsp[-6].minor.yy331, 1); sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS; + /* Instruct SQL to initate Tarantool's transaction. */ + pParse->initiateTTrans = true; sqlite3Insert(pParse, yymsp[-3].minor.yy347, 0, yymsp[-2].minor.yy180, yymsp[-5].minor.yy392); } -#line 3119 "parse.c" +#line 3127 "parse.c" break; case 148: /* idlist_opt ::= LP idlist RP */ -#line 817 "parse.y" +#line 829 "parse.y" {yymsp[-2].minor.yy180 = yymsp[-1].minor.yy180;} -#line 3124 "parse.c" +#line 3132 "parse.c" break; case 149: /* idlist ::= idlist COMMA nm */ -#line 819 "parse.y" +#line 831 "parse.y" {yymsp[-2].minor.yy180 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy180,&yymsp[0].minor.yy0);} -#line 3129 "parse.c" +#line 3137 "parse.c" break; case 150: /* idlist ::= nm */ -#line 821 "parse.y" +#line 833 "parse.y" {yymsp[0].minor.yy180 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} -#line 3134 "parse.c" +#line 3142 "parse.c" break; case 151: /* expr ::= LP expr RP */ -#line 871 "parse.y" +#line 883 "parse.y" {spanSet(&yymsp[-2].minor.yy342,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ yymsp[-2].minor.yy342.pExpr = yymsp[-1].minor.yy342.pExpr;} -#line 3139 "parse.c" +#line 3147 "parse.c" break; case 152: /* term ::= NULL */ case 157: /* term ::= FLOAT|BLOB */ yytestcase(yyruleno==157); case 158: /* term ::= STRING */ yytestcase(yyruleno==158); -#line 872 "parse.y" +#line 884 "parse.y" {spanExpr(&yymsp[0].minor.yy342,pParse,yymsp[0].major,yymsp[0].minor.yy0);/*A-overwrites-X*/} -#line 3146 "parse.c" +#line 3154 "parse.c" break; case 153: /* expr ::= ID|INDEXED */ case 154: /* expr ::= JOIN_KW */ yytestcase(yyruleno==154); -#line 873 "parse.y" +#line 885 "parse.y" {spanExpr(&yymsp[0].minor.yy342,pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} -#line 3152 "parse.c" +#line 3160 "parse.c" break; case 155: /* expr ::= nm DOT nm */ -#line 875 "parse.y" +#line 887 "parse.y" { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); spanSet(&yymsp[-2].minor.yy342,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ yymsp[-2].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); } -#line 3162 "parse.c" +#line 3170 "parse.c" break; case 156: /* expr ::= nm DOT nm DOT nm */ -#line 881 "parse.y" +#line 893 "parse.y" { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); @@ -3170,21 +3178,21 @@ static void yy_reduce( spanSet(&yymsp[-4].minor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); } -#line 3174 "parse.c" +#line 3182 "parse.c" break; case 159: /* term ::= INTEGER */ -#line 891 "parse.y" +#line 903 "parse.y" { yylhsminor.yy342.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); yylhsminor.yy342.zStart = yymsp[0].minor.yy0.z; yylhsminor.yy342.zEnd = yymsp[0].minor.yy0.z + yymsp[0].minor.yy0.n; if( yylhsminor.yy342.pExpr ) yylhsminor.yy342.pExpr->flags |= EP_Leaf; } -#line 3184 "parse.c" +#line 3192 "parse.c" yymsp[0].minor.yy342 = yylhsminor.yy342; break; case 160: /* expr ::= VARIABLE */ -#line 897 "parse.y" +#line 909 "parse.y" { if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ u32 n = yymsp[0].minor.yy0.n; @@ -3206,27 +3214,27 @@ static void yy_reduce( } } } -#line 3210 "parse.c" +#line 3218 "parse.c" break; case 161: /* expr ::= expr COLLATE ID|STRING */ -#line 918 "parse.y" +#line 930 "parse.y" { yymsp[-2].minor.yy342.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy342.pExpr, &yymsp[0].minor.yy0, 1); yymsp[-2].minor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } -#line 3218 "parse.c" +#line 3226 "parse.c" break; case 162: /* expr ::= CAST LP expr AS typetoken RP */ -#line 923 "parse.y" +#line 935 "parse.y" { spanSet(&yymsp[-5].minor.yy342,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ yymsp[-5].minor.yy342.pExpr = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy342.pExpr, yymsp[-3].minor.yy342.pExpr, 0); } -#line 3227 "parse.c" +#line 3235 "parse.c" break; case 163: /* expr ::= ID|INDEXED LP distinct exprlist RP */ -#line 929 "parse.y" +#line 941 "parse.y" { if( yymsp[-1].minor.yy442 && yymsp[-1].minor.yy442->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0); @@ -3237,29 +3245,29 @@ static void yy_reduce( yylhsminor.yy342.pExpr->flags |= EP_Distinct; } } -#line 3241 "parse.c" +#line 3249 "parse.c" yymsp[-4].minor.yy342 = yylhsminor.yy342; break; case 164: /* expr ::= ID|INDEXED LP STAR RP */ -#line 939 "parse.y" +#line 951 "parse.y" { yylhsminor.yy342.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0); spanSet(&yylhsminor.yy342,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); } -#line 3250 "parse.c" +#line 3258 "parse.c" yymsp[-3].minor.yy342 = yylhsminor.yy342; break; case 165: /* term ::= CTIME_KW */ -#line 943 "parse.y" +#line 955 "parse.y" { yylhsminor.yy342.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0); spanSet(&yylhsminor.yy342, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0); } -#line 3259 "parse.c" +#line 3267 "parse.c" yymsp[0].minor.yy342 = yylhsminor.yy342; break; case 166: /* expr ::= LP nexprlist COMMA expr RP */ -#line 972 "parse.y" +#line 984 "parse.y" { ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy442, yymsp[-1].minor.yy342.pExpr); yylhsminor.yy342.pExpr = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); @@ -3270,7 +3278,7 @@ static void yy_reduce( sqlite3ExprListDelete(pParse->db, pList); } } -#line 3274 "parse.c" +#line 3282 "parse.c" yymsp[-4].minor.yy342 = yylhsminor.yy342; break; case 167: /* expr ::= expr AND expr */ @@ -3281,22 +3289,22 @@ static void yy_reduce( case 172: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==172); case 173: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==173); case 174: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==174); -#line 983 "parse.y" +#line 995 "parse.y" {spanBinaryExpr(pParse,yymsp[-1].major,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy342);} -#line 3287 "parse.c" +#line 3295 "parse.c" break; case 175: /* likeop ::= LIKE_KW|MATCH */ -#line 996 "parse.y" +#line 1008 "parse.y" {yymsp[0].minor.yy0=yymsp[0].minor.yy0;/*A-overwrites-X*/} -#line 3292 "parse.c" +#line 3300 "parse.c" break; case 176: /* likeop ::= NOT LIKE_KW|MATCH */ -#line 997 "parse.y" +#line 1009 "parse.y" {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} -#line 3297 "parse.c" +#line 3305 "parse.c" break; case 177: /* expr ::= expr likeop expr */ -#line 998 "parse.y" +#line 1010 "parse.y" { ExprList *pList; int bNot = yymsp[-1].minor.yy0.n & 0x80000000; @@ -3308,10 +3316,10 @@ static void yy_reduce( yymsp[-2].minor.yy342.zEnd = yymsp[0].minor.yy342.zEnd; if( yymsp[-2].minor.yy342.pExpr ) yymsp[-2].minor.yy342.pExpr->flags |= EP_InfixFunc; } -#line 3312 "parse.c" +#line 3320 "parse.c" break; case 178: /* expr ::= expr likeop expr ESCAPE expr */ -#line 1009 "parse.y" +#line 1021 "parse.y" { ExprList *pList; int bNot = yymsp[-3].minor.yy0.n & 0x80000000; @@ -3324,58 +3332,58 @@ static void yy_reduce( yymsp[-4].minor.yy342.zEnd = yymsp[0].minor.yy342.zEnd; if( yymsp[-4].minor.yy342.pExpr ) yymsp[-4].minor.yy342.pExpr->flags |= EP_InfixFunc; } -#line 3328 "parse.c" +#line 3336 "parse.c" break; case 179: /* expr ::= expr ISNULL|NOTNULL */ -#line 1036 "parse.y" +#line 1048 "parse.y" {spanUnaryPostfix(pParse,yymsp[0].major,&yymsp[-1].minor.yy342,&yymsp[0].minor.yy0);} -#line 3333 "parse.c" +#line 3341 "parse.c" break; case 180: /* expr ::= expr NOT NULL */ -#line 1037 "parse.y" +#line 1049 "parse.y" {spanUnaryPostfix(pParse,TK_NOTNULL,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy0);} -#line 3338 "parse.c" +#line 3346 "parse.c" break; case 181: /* expr ::= expr IS expr */ -#line 1058 "parse.y" +#line 1070 "parse.y" { spanBinaryExpr(pParse,TK_IS,&yymsp[-2].minor.yy342,&yymsp[0].minor.yy342); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy342.pExpr, yymsp[-2].minor.yy342.pExpr, TK_ISNULL); } -#line 3346 "parse.c" +#line 3354 "parse.c" break; case 182: /* expr ::= expr IS NOT expr */ -#line 1062 "parse.y" +#line 1074 "parse.y" { spanBinaryExpr(pParse,TK_ISNOT,&yymsp[-3].minor.yy342,&yymsp[0].minor.yy342); binaryToUnaryIfNull(pParse, yymsp[0].minor.yy342.pExpr, yymsp[-3].minor.yy342.pExpr, TK_NOTNULL); } -#line 3354 "parse.c" +#line 3362 "parse.c" break; case 183: /* expr ::= NOT expr */ case 184: /* expr ::= BITNOT expr */ yytestcase(yyruleno==184); -#line 1086 "parse.y" +#line 1098 "parse.y" {spanUnaryPrefix(&yymsp[-1].minor.yy342,pParse,yymsp[-1].major,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} -#line 3360 "parse.c" +#line 3368 "parse.c" break; case 185: /* expr ::= MINUS expr */ -#line 1090 "parse.y" +#line 1102 "parse.y" {spanUnaryPrefix(&yymsp[-1].minor.yy342,pParse,TK_UMINUS,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} -#line 3365 "parse.c" +#line 3373 "parse.c" break; case 186: /* expr ::= PLUS expr */ -#line 1092 "parse.y" +#line 1104 "parse.y" {spanUnaryPrefix(&yymsp[-1].minor.yy342,pParse,TK_UPLUS,&yymsp[0].minor.yy342,&yymsp[-1].minor.yy0);/*A-overwrites-B*/} -#line 3370 "parse.c" +#line 3378 "parse.c" break; case 187: /* between_op ::= BETWEEN */ case 190: /* in_op ::= IN */ yytestcase(yyruleno==190); -#line 1095 "parse.y" +#line 1107 "parse.y" {yymsp[0].minor.yy392 = 0;} -#line 3376 "parse.c" +#line 3384 "parse.c" break; case 189: /* expr ::= expr between_op expr AND expr */ -#line 1097 "parse.y" +#line 1109 "parse.y" { ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy342.pExpr); pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy342.pExpr); @@ -3388,10 +3396,10 @@ static void yy_reduce( exprNot(pParse, yymsp[-3].minor.yy392, &yymsp[-4].minor.yy342); yymsp[-4].minor.yy342.zEnd = yymsp[0].minor.yy342.zEnd; } -#line 3392 "parse.c" +#line 3400 "parse.c" break; case 192: /* expr ::= expr in_op LP exprlist RP */ -#line 1113 "parse.y" +#line 1125 "parse.y" { if( yymsp[-1].minor.yy442==0 ){ /* Expressions of the form @@ -3443,29 +3451,29 @@ static void yy_reduce( } yymsp[-4].minor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } -#line 3447 "parse.c" +#line 3455 "parse.c" break; case 193: /* expr ::= LP select RP */ -#line 1164 "parse.y" +#line 1176 "parse.y" { spanSet(&yymsp[-2].minor.yy342,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ yymsp[-2].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0); sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy342.pExpr, yymsp[-1].minor.yy159); } -#line 3456 "parse.c" +#line 3464 "parse.c" break; case 194: /* expr ::= expr in_op LP select RP */ -#line 1169 "parse.y" +#line 1181 "parse.y" { yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy342.pExpr, 0); sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy342.pExpr, yymsp[-1].minor.yy159); exprNot(pParse, yymsp[-3].minor.yy392, &yymsp[-4].minor.yy342); yymsp[-4].minor.yy342.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n]; } -#line 3466 "parse.c" +#line 3474 "parse.c" break; case 195: /* expr ::= expr in_op nm dbnm paren_exprlist */ -#line 1175 "parse.y" +#line 1187 "parse.y" { SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0); @@ -3475,20 +3483,20 @@ static void yy_reduce( exprNot(pParse, yymsp[-3].minor.yy392, &yymsp[-4].minor.yy342); yymsp[-4].minor.yy342.zEnd = yymsp[-1].minor.yy0.z ? &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n] : &yymsp[-2].minor.yy0.z[yymsp[-2].minor.yy0.n]; } -#line 3479 "parse.c" +#line 3487 "parse.c" break; case 196: /* expr ::= EXISTS LP select RP */ -#line 1184 "parse.y" +#line 1196 "parse.y" { Expr *p; spanSet(&yymsp[-3].minor.yy342,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ p = yymsp[-3].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy159); } -#line 3489 "parse.c" +#line 3497 "parse.c" break; case 197: /* expr ::= CASE case_operand case_exprlist case_else END */ -#line 1193 "parse.y" +#line 1205 "parse.y" { spanSet(&yymsp[-4].minor.yy342,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-C*/ yymsp[-4].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy122, 0); @@ -3500,237 +3508,237 @@ static void yy_reduce( sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy122); } } -#line 3504 "parse.c" +#line 3512 "parse.c" break; case 198: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ -#line 1206 "parse.y" +#line 1218 "parse.y" { yymsp[-4].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy442, yymsp[-2].minor.yy342.pExpr); yymsp[-4].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy442, yymsp[0].minor.yy342.pExpr); } -#line 3512 "parse.c" +#line 3520 "parse.c" break; case 199: /* case_exprlist ::= WHEN expr THEN expr */ -#line 1210 "parse.y" +#line 1222 "parse.y" { yymsp[-3].minor.yy442 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy342.pExpr); yymsp[-3].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy442, yymsp[0].minor.yy342.pExpr); } -#line 3520 "parse.c" +#line 3528 "parse.c" break; case 202: /* case_operand ::= expr */ -#line 1220 "parse.y" +#line 1232 "parse.y" {yymsp[0].minor.yy122 = yymsp[0].minor.yy342.pExpr; /*A-overwrites-X*/} -#line 3525 "parse.c" +#line 3533 "parse.c" break; case 205: /* nexprlist ::= nexprlist COMMA expr */ -#line 1231 "parse.y" +#line 1243 "parse.y" {yymsp[-2].minor.yy442 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy442,yymsp[0].minor.yy342.pExpr);} -#line 3530 "parse.c" +#line 3538 "parse.c" break; case 206: /* nexprlist ::= expr */ -#line 1233 "parse.y" +#line 1245 "parse.y" {yymsp[0].minor.yy442 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy342.pExpr); /*A-overwrites-Y*/} -#line 3535 "parse.c" +#line 3543 "parse.c" break; case 208: /* paren_exprlist ::= LP exprlist RP */ case 213: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==213); -#line 1241 "parse.y" +#line 1253 "parse.y" {yymsp[-2].minor.yy442 = yymsp[-1].minor.yy442;} -#line 3541 "parse.c" +#line 3549 "parse.c" break; case 209: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ -#line 1248 "parse.y" +#line 1260 "parse.y" { sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy442, yymsp[-10].minor.yy392, &yymsp[-11].minor.yy0, yymsp[0].minor.yy122, SQLITE_SO_ASC, yymsp[-8].minor.yy392, SQLITE_IDXTYPE_APPDEF); } -#line 3550 "parse.c" +#line 3558 "parse.c" break; case 210: /* uniqueflag ::= UNIQUE */ case 249: /* raisetype ::= ABORT */ yytestcase(yyruleno==249); -#line 1255 "parse.y" +#line 1267 "parse.y" {yymsp[0].minor.yy392 = OE_Abort;} -#line 3556 "parse.c" +#line 3564 "parse.c" break; case 211: /* uniqueflag ::= */ -#line 1256 "parse.y" +#line 1268 "parse.y" {yymsp[1].minor.yy392 = OE_None;} -#line 3561 "parse.c" +#line 3569 "parse.c" break; case 214: /* eidlist ::= eidlist COMMA nm collate sortorder */ -#line 1306 "parse.y" +#line 1318 "parse.y" { yymsp[-4].minor.yy442 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy442, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy392, yymsp[0].minor.yy392); } -#line 3568 "parse.c" +#line 3576 "parse.c" break; case 215: /* eidlist ::= nm collate sortorder */ -#line 1309 "parse.y" +#line 1321 "parse.y" { yymsp[-2].minor.yy442 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy392, yymsp[0].minor.yy392); /*A-overwrites-Y*/ } -#line 3575 "parse.c" +#line 3583 "parse.c" break; case 218: /* cmd ::= DROP INDEX ifexists fullname */ -#line 1320 "parse.y" +#line 1332 "parse.y" {sqlite3DropIndex(pParse, yymsp[0].minor.yy347, yymsp[-1].minor.yy392);} -#line 3580 "parse.c" +#line 3588 "parse.c" break; case 219: /* cmd ::= PRAGMA nm dbnm */ -#line 1334 "parse.y" +#line 1346 "parse.y" {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} -#line 3585 "parse.c" +#line 3593 "parse.c" break; case 220: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ -#line 1335 "parse.y" +#line 1347 "parse.y" {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} -#line 3590 "parse.c" +#line 3598 "parse.c" break; case 221: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ -#line 1336 "parse.y" +#line 1348 "parse.y" {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} -#line 3595 "parse.c" +#line 3603 "parse.c" break; case 222: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ -#line 1338 "parse.y" +#line 1350 "parse.y" {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} -#line 3600 "parse.c" +#line 3608 "parse.c" break; case 223: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ -#line 1340 "parse.y" +#line 1352 "parse.y" {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} -#line 3605 "parse.c" +#line 3613 "parse.c" break; case 226: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ -#line 1356 "parse.y" +#line 1368 "parse.y" { Token all; all.z = yymsp[-3].minor.yy0.z; all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n; sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy327, &all); } -#line 3615 "parse.c" +#line 3623 "parse.c" break; case 227: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ -#line 1365 "parse.y" +#line 1377 "parse.y" { sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy392, yymsp[-4].minor.yy410.a, yymsp[-4].minor.yy410.b, yymsp[-2].minor.yy347, yymsp[0].minor.yy122, yymsp[-10].minor.yy392, yymsp[-8].minor.yy392); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ } -#line 3623 "parse.c" +#line 3631 "parse.c" break; case 228: /* trigger_time ::= BEFORE */ -#line 1371 "parse.y" +#line 1383 "parse.y" { yymsp[0].minor.yy392 = TK_BEFORE; } -#line 3628 "parse.c" +#line 3636 "parse.c" break; case 229: /* trigger_time ::= AFTER */ -#line 1372 "parse.y" +#line 1384 "parse.y" { yymsp[0].minor.yy392 = TK_AFTER; } -#line 3633 "parse.c" +#line 3641 "parse.c" break; case 230: /* trigger_time ::= INSTEAD OF */ -#line 1373 "parse.y" +#line 1385 "parse.y" { yymsp[-1].minor.yy392 = TK_INSTEAD;} -#line 3638 "parse.c" +#line 3646 "parse.c" break; case 231: /* trigger_time ::= */ -#line 1374 "parse.y" +#line 1386 "parse.y" { yymsp[1].minor.yy392 = TK_BEFORE; } -#line 3643 "parse.c" +#line 3651 "parse.c" break; case 232: /* trigger_event ::= DELETE|INSERT */ case 233: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==233); -#line 1378 "parse.y" +#line 1390 "parse.y" {yymsp[0].minor.yy410.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy410.b = 0;} -#line 3649 "parse.c" +#line 3657 "parse.c" break; case 234: /* trigger_event ::= UPDATE OF idlist */ -#line 1380 "parse.y" +#line 1392 "parse.y" {yymsp[-2].minor.yy410.a = TK_UPDATE; yymsp[-2].minor.yy410.b = yymsp[0].minor.yy180;} -#line 3654 "parse.c" +#line 3662 "parse.c" break; case 235: /* when_clause ::= */ case 254: /* key_opt ::= */ yytestcase(yyruleno==254); -#line 1387 "parse.y" +#line 1399 "parse.y" { yymsp[1].minor.yy122 = 0; } -#line 3660 "parse.c" +#line 3668 "parse.c" break; case 236: /* when_clause ::= WHEN expr */ case 255: /* key_opt ::= KEY expr */ yytestcase(yyruleno==255); -#line 1388 "parse.y" +#line 1400 "parse.y" { yymsp[-1].minor.yy122 = yymsp[0].minor.yy342.pExpr; } -#line 3666 "parse.c" +#line 3674 "parse.c" break; case 237: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ -#line 1392 "parse.y" +#line 1404 "parse.y" { assert( yymsp[-2].minor.yy327!=0 ); yymsp[-2].minor.yy327->pLast->pNext = yymsp[-1].minor.yy327; yymsp[-2].minor.yy327->pLast = yymsp[-1].minor.yy327; } -#line 3675 "parse.c" +#line 3683 "parse.c" break; case 238: /* trigger_cmd_list ::= trigger_cmd SEMI */ -#line 1397 "parse.y" +#line 1409 "parse.y" { assert( yymsp[-1].minor.yy327!=0 ); yymsp[-1].minor.yy327->pLast = yymsp[-1].minor.yy327; } -#line 3683 "parse.c" +#line 3691 "parse.c" break; case 239: /* trnm ::= nm DOT nm */ -#line 1408 "parse.y" +#line 1420 "parse.y" { yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; sqlite3ErrorMsg(pParse, "qualified table names are not allowed on INSERT, UPDATE, and DELETE " "statements within triggers"); } -#line 3693 "parse.c" +#line 3701 "parse.c" break; case 240: /* tridxby ::= INDEXED BY nm */ -#line 1420 "parse.y" +#line 1432 "parse.y" { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } -#line 3702 "parse.c" +#line 3710 "parse.c" break; case 241: /* tridxby ::= NOT INDEXED */ -#line 1425 "parse.y" +#line 1437 "parse.y" { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } -#line 3711 "parse.c" +#line 3719 "parse.c" break; case 242: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */ -#line 1438 "parse.y" +#line 1450 "parse.y" {yymsp[-6].minor.yy327 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy442, yymsp[0].minor.yy122, yymsp[-5].minor.yy392);} -#line 3716 "parse.c" +#line 3724 "parse.c" break; case 243: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */ -#line 1442 "parse.y" +#line 1454 "parse.y" {yymsp[-4].minor.yy327 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy180, yymsp[0].minor.yy159, yymsp[-4].minor.yy392);/*A-overwrites-R*/} -#line 3721 "parse.c" +#line 3729 "parse.c" break; case 244: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */ -#line 1446 "parse.y" +#line 1458 "parse.y" {yymsp[-4].minor.yy327 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy122);} -#line 3726 "parse.c" +#line 3734 "parse.c" break; case 245: /* trigger_cmd ::= select */ -#line 1450 "parse.y" +#line 1462 "parse.y" {yymsp[0].minor.yy327 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy159); /*A-overwrites-X*/} -#line 3731 "parse.c" +#line 3739 "parse.c" break; case 246: /* expr ::= RAISE LP IGNORE RP */ -#line 1453 "parse.y" +#line 1465 "parse.y" { spanSet(&yymsp[-3].minor.yy342,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ yymsp[-3].minor.yy342.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0); @@ -3738,10 +3746,10 @@ static void yy_reduce( yymsp[-3].minor.yy342.pExpr->affinity = OE_Ignore; } } -#line 3742 "parse.c" +#line 3750 "parse.c" break; case 247: /* expr ::= RAISE LP raisetype COMMA nm RP */ -#line 1460 "parse.y" +#line 1472 "parse.y" { spanSet(&yymsp[-5].minor.yy342,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/ yymsp[-5].minor.yy342.pExpr = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); @@ -3749,139 +3757,139 @@ static void yy_reduce( yymsp[-5].minor.yy342.pExpr->affinity = (char)yymsp[-3].minor.yy392; } } -#line 3753 "parse.c" +#line 3761 "parse.c" break; case 248: /* raisetype ::= ROLLBACK */ -#line 1470 "parse.y" +#line 1482 "parse.y" {yymsp[0].minor.yy392 = OE_Rollback;} -#line 3758 "parse.c" +#line 3766 "parse.c" break; case 250: /* raisetype ::= FAIL */ -#line 1472 "parse.y" +#line 1484 "parse.y" {yymsp[0].minor.yy392 = OE_Fail;} -#line 3763 "parse.c" +#line 3771 "parse.c" break; case 251: /* cmd ::= DROP TRIGGER ifexists fullname */ -#line 1477 "parse.y" +#line 1489 "parse.y" { sqlite3DropTrigger(pParse,yymsp[0].minor.yy347,yymsp[-1].minor.yy392); } -#line 3770 "parse.c" +#line 3778 "parse.c" break; case 252: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ -#line 1484 "parse.y" +#line 1496 "parse.y" { sqlite3Attach(pParse, yymsp[-3].minor.yy342.pExpr, yymsp[-1].minor.yy342.pExpr, yymsp[0].minor.yy122); } -#line 3777 "parse.c" +#line 3785 "parse.c" break; case 253: /* cmd ::= DETACH database_kw_opt expr */ -#line 1487 "parse.y" +#line 1499 "parse.y" { sqlite3Detach(pParse, yymsp[0].minor.yy342.pExpr); } -#line 3784 "parse.c" +#line 3792 "parse.c" break; case 256: /* cmd ::= REINDEX */ -#line 1502 "parse.y" +#line 1514 "parse.y" {sqlite3Reindex(pParse, 0, 0);} -#line 3789 "parse.c" +#line 3797 "parse.c" break; case 257: /* cmd ::= REINDEX nm dbnm */ -#line 1503 "parse.y" +#line 1515 "parse.y" {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} -#line 3794 "parse.c" +#line 3802 "parse.c" break; case 258: /* cmd ::= ANALYZE */ -#line 1508 "parse.y" +#line 1520 "parse.y" {sqlite3Analyze(pParse, 0, 0);} -#line 3799 "parse.c" +#line 3807 "parse.c" break; case 259: /* cmd ::= ANALYZE nm dbnm */ -#line 1509 "parse.y" +#line 1521 "parse.y" {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} -#line 3804 "parse.c" +#line 3812 "parse.c" break; case 260: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ -#line 1514 "parse.y" +#line 1526 "parse.y" { sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy347,&yymsp[0].minor.yy0); } -#line 3811 "parse.c" +#line 3819 "parse.c" break; case 261: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ -#line 1518 "parse.y" +#line 1530 "parse.y" { yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); } -#line 3819 "parse.c" +#line 3827 "parse.c" break; case 262: /* add_column_fullname ::= fullname */ -#line 1522 "parse.y" +#line 1534 "parse.y" { disableLookaside(pParse); sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy347); } -#line 3827 "parse.c" +#line 3835 "parse.c" break; case 263: /* cmd ::= create_vtab */ -#line 1532 "parse.y" +#line 1544 "parse.y" {sqlite3VtabFinishParse(pParse,0);} -#line 3832 "parse.c" +#line 3840 "parse.c" break; case 264: /* cmd ::= create_vtab LP vtabarglist RP */ -#line 1533 "parse.y" +#line 1545 "parse.y" {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} -#line 3837 "parse.c" +#line 3845 "parse.c" break; case 265: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ -#line 1535 "parse.y" +#line 1547 "parse.y" { sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy392); } -#line 3844 "parse.c" +#line 3852 "parse.c" break; case 266: /* vtabarg ::= */ -#line 1540 "parse.y" +#line 1552 "parse.y" {sqlite3VtabArgInit(pParse);} -#line 3849 "parse.c" +#line 3857 "parse.c" break; case 267: /* vtabargtoken ::= ANY */ case 268: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==268); case 269: /* lp ::= LP */ yytestcase(yyruleno==269); -#line 1542 "parse.y" +#line 1554 "parse.y" {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} -#line 3856 "parse.c" +#line 3864 "parse.c" break; case 270: /* with ::= */ -#line 1557 "parse.y" +#line 1569 "parse.y" {yymsp[1].minor.yy331 = 0;} -#line 3861 "parse.c" +#line 3869 "parse.c" break; case 271: /* with ::= WITH wqlist */ -#line 1559 "parse.y" +#line 1571 "parse.y" { yymsp[-1].minor.yy331 = yymsp[0].minor.yy331; } -#line 3866 "parse.c" +#line 3874 "parse.c" break; case 272: /* with ::= WITH RECURSIVE wqlist */ -#line 1560 "parse.y" +#line 1572 "parse.y" { yymsp[-2].minor.yy331 = yymsp[0].minor.yy331; } -#line 3871 "parse.c" +#line 3879 "parse.c" break; case 273: /* wqlist ::= nm eidlist_opt AS LP select RP */ -#line 1562 "parse.y" +#line 1574 "parse.y" { yymsp[-5].minor.yy331 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy442, yymsp[-1].minor.yy159); /*A-overwrites-X*/ } -#line 3878 "parse.c" +#line 3886 "parse.c" break; case 274: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ -#line 1565 "parse.y" +#line 1577 "parse.y" { yymsp[-7].minor.yy331 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy331, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy442, yymsp[-1].minor.yy159); } -#line 3885 "parse.c" +#line 3893 "parse.c" break; default: /* (275) input ::= ecmd */ yytestcase(yyruleno==275); @@ -3998,7 +4006,7 @@ static void yy_syntax_error( UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */ assert( TOKEN.z[0] ); /* The tokenizer always gives us a token */ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN); -#line 4002 "parse.c" +#line 4010 "parse.c" /************ End %syntax_error code ******************************************/ sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ } diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y index aba17923b4..d4e4e25e48 100644 --- a/src/box/sql/parse.y +++ b/src/box/sql/parse.y @@ -730,6 +730,8 @@ cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W) sqlite3SrcListIndexedBy(pParse, X, &I); W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "DELETE"); sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS; + /* Instruct SQL to initate Tarantool's transaction. */ + pParse->initiateTTrans = true; sqlite3DeleteFrom(pParse,X,W); } %endif @@ -738,6 +740,8 @@ cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W). { sqlite3WithPush(pParse, C, 1); sqlite3SrcListIndexedBy(pParse, X, &I); sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS; + /* Instruct SQL to initate Tarantool's transaction. */ + pParse->initiateTTrans = true; sqlite3DeleteFrom(pParse,X,W); } %endif @@ -758,6 +762,8 @@ cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) sqlite3ExprListCheckLength(pParse,Y,"set list"); W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "UPDATE"); sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS; + /* Instruct SQL to initate Tarantool's transaction. */ + pParse->initiateTTrans = true; sqlite3Update(pParse,X,Y,W,R); } %endif @@ -768,6 +774,8 @@ cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3ExprListCheckLength(pParse,Y,"set list"); sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS; + /* Instruct SQL to initate Tarantool's transaction. */ + pParse->initiateTTrans = true; sqlite3Update(pParse,X,Y,W,R); } %endif @@ -795,12 +803,16 @@ setlist(A) ::= LP idlist(X) RP EQ expr(Y). { cmd ::= with(W) insert_cmd(R) INTO fullname(X) idlist_opt(F) select(S). { sqlite3WithPush(pParse, W, 1); sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS; + /* Instruct SQL to initate Tarantool's transaction. */ + pParse->initiateTTrans = true; sqlite3Insert(pParse, X, S, F, R); } cmd ::= with(W) insert_cmd(R) INTO fullname(X) idlist_opt(F) DEFAULT VALUES. { sqlite3WithPush(pParse, W, 1); sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS; + /* Instruct SQL to initate Tarantool's transaction. */ + pParse->initiateTTrans = true; sqlite3Insert(pParse, X, 0, F, R); } diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h index 53d17aa589..d96d1f56f3 100644 --- a/src/box/sql/sqliteInt.h +++ b/src/box/sql/sqliteInt.h @@ -42,6 +42,8 @@ ** asterisks and the comment text. */ +#include <stdbool.h> + /* ** Make sure the Tcl calling convention macro is defined. This macro is ** only used by test code and Tcl integration code. @@ -2961,6 +2963,8 @@ struct Parse { TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ With *pWith; /* Current WITH clause, or NULL */ With *pWithToFree; /* Free this WITH object at the end of the parse */ + + bool initiateTTrans; /* Initiate Tarantool transaction */ }; /* diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c index a49783d54b..a2fbca34f2 100644 --- a/src/box/sql/trigger.c +++ b/src/box/sql/trigger.c @@ -10,6 +10,7 @@ ************************************************************************* ** This file contains the implementation for TRIGGERs */ + #include "sqliteInt.h" #include "tarantoolInt.h" #include "vdbeInt.h" @@ -778,25 +779,25 @@ static int codeTriggerProgram( switch( pStep->op ){ case TK_UPDATE: { - sqlite3Update(pParse, + sqlite3Update(pParse, targetSrcList(pParse, pStep), - sqlite3ExprListDup(db, pStep->pExprList, 0), - sqlite3ExprDup(db, pStep->pWhere, 0), + sqlite3ExprListDup(db, pStep->pExprList, 0), + sqlite3ExprDup(db, pStep->pWhere, 0), pParse->eOrconf ); break; } case TK_INSERT: { - sqlite3Insert(pParse, + sqlite3Insert(pParse, targetSrcList(pParse, pStep), - sqlite3SelectDup(db, pStep->pSelect, 0), - sqlite3IdListDup(db, pStep->pIdList), + sqlite3SelectDup(db, pStep->pSelect, 0), + sqlite3IdListDup(db, pStep->pIdList), pParse->eOrconf ); break; } case TK_DELETE: { - sqlite3DeleteFrom(pParse, + sqlite3DeleteFrom(pParse, targetSrcList(pParse, pStep), sqlite3ExprDup(db, pStep->pWhere, 0) ); diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 82a292e908..3aabab7858 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -3119,6 +3119,21 @@ case OP_Transaction: { break; } +/* Opcode: TTransaction * * * * * +** +** Start Tarantool's transaction. +** Only do that if auto commit mode is on. This should be no-op +** if this opcode was emitted inside a transaction. +** Auto commit mode is disabled by OP_Transaction. +*/ +case OP_TTransaction: + { + int rc; + if (db->autoCommit) + rc = box_txn_begin() == 0 ? SQLITE_OK : SQLITE_TARANTOOL_ERROR; + break; + } + /* Opcode: ReadCookie P1 P2 P3 * * ** ** Read cookie number P3 from database P1 and write it into register P2. diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c index 4f5a35e44b..e5bf323461 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -2112,14 +2112,10 @@ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ } /* -** Close all cursors. +** Close top frame cursors. ** -** Also release any dynamic memory held by the VM in the Vdbe.aMem memory -** cell array. This is necessary as the memory cell array may contain -** pointers to VdbeFrame objects, which may in turn contain pointers to -** open cursors. */ -static void closeAllCursors(Vdbe *p){ +static void closeTopFrameCursors(Vdbe *p){ if( p->pFrame ){ VdbeFrame *pFrame; for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); @@ -2129,6 +2125,19 @@ static void closeAllCursors(Vdbe *p){ } assert( p->nFrame==0 ); closeCursorsInFrame(p); +} + +/* +** Close cursors in frames marked for deletetion and free memory +** +** Delete all frames marked for deletion, which in turn will cause in-frame +** cursors to be closed. +** Also release any dynamic memory held by the VM in the Vdbe.aMem memory +** cell array. This is necessary as the memory cell array may contain +** pointers to VdbeFrame objects, which may in turn contain pointers to +** open cursors. +*/ +static void closeCursorsAndFree(Vdbe *p){ if( p->aMem ){ releaseMemArray(p->aMem, p->nMem); } @@ -2632,7 +2641,7 @@ int sqlite3VdbeHalt(Vdbe *p){ if( db->mallocFailed ){ p->rc = SQLITE_NOMEM_BKPT; } - closeAllCursors(p); + closeTopFrameCursors(p); if( p->magic!=VDBE_MAGIC_RUN ){ return SQLITE_OK; } @@ -2672,6 +2681,8 @@ int sqlite3VdbeHalt(Vdbe *p){ /* We are forced to roll back the active transaction. Before doing ** so, abort any other statements this handle currently has active. */ + box_txn_rollback(); + closeCursorsAndFree(p); sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; @@ -2699,6 +2710,7 @@ int sqlite3VdbeHalt(Vdbe *p){ rc = sqlite3VdbeCheckFk(p, 1); if( rc!=SQLITE_OK ){ if( NEVER(p->readOnly) ){ + closeCursorsAndFree(p); sqlite3VdbeLeave(p); return SQLITE_ERROR; } @@ -2709,12 +2721,18 @@ int sqlite3VdbeHalt(Vdbe *p){ ** key constraints to hold up the transaction. This means a commit ** is required. */ rc = vdbeCommit(db, p); + if (rc == SQLITE_OK) + rc = box_txn_commit() == 0? SQLITE_OK : SQLITE_TARANTOOL_ERROR; + closeCursorsAndFree(p); } if( rc==SQLITE_BUSY && p->readOnly ){ + closeCursorsAndFree(p); sqlite3VdbeLeave(p); return SQLITE_BUSY; }else if( rc!=SQLITE_OK ){ p->rc = rc; + box_txn_rollback(); + closeCursorsAndFree(p); sqlite3RollbackAll(db, SQLITE_OK); p->nChange = 0; }else{ @@ -2724,6 +2742,8 @@ int sqlite3VdbeHalt(Vdbe *p){ sqlite3CommitInternalChanges(db); } }else{ + box_txn_rollback(); + closeCursorsAndFree(p); sqlite3RollbackAll(db, SQLITE_OK); p->nChange = 0; } @@ -2734,6 +2754,8 @@ int sqlite3VdbeHalt(Vdbe *p){ }else if( p->errorAction==OE_Abort ){ eStatementOp = SAVEPOINT_ROLLBACK; }else{ + box_txn_rollback(); + closeCursorsAndFree(p); sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; @@ -2750,11 +2772,13 @@ int sqlite3VdbeHalt(Vdbe *p){ if( eStatementOp ){ rc = sqlite3VdbeCloseStatement(p, eStatementOp); if( rc ){ + box_txn_rollback(); if( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ){ p->rc = rc; sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; } + closeCursorsAndFree(p); sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; @@ -2778,6 +2802,8 @@ int sqlite3VdbeHalt(Vdbe *p){ sqlite3VdbeLeave(p); } + closeCursorsAndFree(p); + /* We have successfully halted and closed the VM. Record this fact. */ if( p->pc>=0 ){ db->nVdbeActive--; diff --git a/test/sql-tap/gh2259-in-stmt-trans.test.lua b/test/sql-tap/gh2259-in-stmt-trans.test.lua new file mode 100755 index 0000000000..b0b27b9d4f --- /dev/null +++ b/test/sql-tap/gh2259-in-stmt-trans.test.lua @@ -0,0 +1,84 @@ +#!/usr/bin/env tarantool +test = require("sqltester") +test:plan(20) + +box.sql.execute("DROP TABLE IF EXISTS t1") +box.sql.execute("DROP TABLE IF EXISTS t2") + +box.sql.execute("CREATE TABLE t1 (s1 int primary key, s2 int);") +box.sql.execute("CREATE TABLE t2 (s1 int primary key, s2 int);") + +box.sql.execute("INSERT INTO t2 VALUES (1,1);") +box.sql.execute("INSERT INTO t1 VALUES (3,3);") + +for _, prefix in pairs({"BEFORE", "AFTER"}) do + box.sql.execute('DROP TRIGGER IF EXISTS t1i') + box.sql.execute('CREATE TRIGGER t1i '..prefix..' INSERT ON t1 FOR EACH ROW \ + BEGIN INSERT INTO t2 VALUES (1,1); END') + + test:do_catchsql_test(prefix..'_insert1', + 'INSERT INTO t1 VALUES(1, 2)', + {1,"UNIQUE constraint failed: t2.s1"}) + + test:do_execsql_test(prefix..'_insert1_check1', + 'SELECT * FROM t1', + {3, 3}) + + test:do_execsql_test(prefix..'_insert1_check2', + 'SELECT * FROM t2', + {1, 1}) + + box.sql.execute('DROP TRIGGER IF EXISTS t1u') + box.sql.execute('CREATE TRIGGER t1u '..prefix..' UPDATE ON t1 FOR EACH ROW \ + BEGIN INSERT INTO t2 VALUES (1,1); END') + + test:do_catchsql_test(prefix..'_update1', + 'UPDATE t1 SET s1=1', + {1,"UNIQUE constraint failed: t2.s1"}) + + test:do_execsql_test(prefix..'_update1_check1', + 'SELECT * FROM t1', + {3, 3}) + + test:do_execsql_test(prefix..'_insert1_check2', + 'SELECT * FROM t2', + {1, 1}) + + box.sql.execute('DROP TRIGGER IF EXISTS t1ds') + -- FOR EACH STATEMENT + box.sql.execute('CREATE TRIGGER t1ds '..prefix..' DELETE ON t1 FOR EACH ROW\ + BEGIN INSERT INTO t2 VALUES (2,2); \ + INSERT INTO t2 VALUES (2,2); END') + + test:do_catchsql_test(prefix..'delete1', + 'DELETE FROM t1;', + {1, "UNIQUE constraint failed: t2.s1"}) + + -- Nothing should be inserted due to abort + test:do_execsql_test('delete1_check1', + 'SELECT * FROM t2', + {1, 1}) + + -- Nothing should be deleted + test:do_execsql_test('delete1_check2', + 'SELECT * FROM t1', + {3, 3}) + +end + +-- Check multi-insert +test:do_catchsql_test('insert2', + 'INSERT INTO t1 VALUES (5, 6), (6, 7)', + {1, 'UNIQUE constraint failed: t2.s1'}) +test:do_execsql_test('insert2_check', + 'SELECT * FROM t1;', + {3, 3}) + +-- Cleanup +box.sql.execute('DROP TRIGGER IF EXISTS t1i') +box.sql.execute('DROP TRIGGER IF EXISTS t1u') +box.sql.execute('DROP TRIGGER IF EXISTS t1ds') +box.sql.execute('DROP TABLE t1') +box.sql.execute('DROP TABLE t2') + +test:finish_test() diff --git a/test/sql/persistency.result b/test/sql/persistency.result index c80e3911c7..82f9ddc1e2 100644 --- a/test/sql/persistency.result +++ b/test/sql/persistency.result @@ -143,6 +143,26 @@ box.sql.execute("SELECT * FROM _trigger"); --- - - ['tfoobar', !!binary gaNzcWzZaUNSRUFURSBUUklHR0VSIHRmb29iYXIgQUZURVIgSU5TRVJUIE9OIGZvb2JhciBCRUdJTiBJTlNFUlQgSU5UTyBiYXJmb28gVkFMVUVTICgndHJpZ2dlciB0ZXN0JywgOTk5OSk7IEVORA==] ... +-- Many entries +box.sql.execute("CREATE TABLE t1(a,b,c,PRIMARY KEY(b,c));") +--- +... +box.sql.execute("WITH RECURSIVE cnt(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM cnt WHERE x<1000) INSERT INTO t1 SELECT x, x%40, x/40 FROM cnt;") +--- +... +box.sql.execute("SELECT a FROM t1 ORDER BY b, a LIMIT 10 OFFSET 20;"); +--- +- - [840] + - [880] + - [920] + - [960] + - [1000] + - [1] + - [41] + - [81] + - [121] + - [161] +... test_run:cmd('restart server default'); -- prove that trigger survived box.sql.execute("SELECT * FROM _trigger"); @@ -195,6 +215,19 @@ box.sql.execute("SELECT * FROM foobar"); - [1000, 'foobar'] - ['foobar trigger test', 8888] ... +box.sql.execute("SELECT a FROM t1 ORDER BY b, a LIMIT 10 OFFSET 20;"); +--- +- - [840] + - [880] + - [920] + - [960] + - [1000] + - [1] + - [41] + - [81] + - [121] + - [161] +... -- cleanup box.sql.execute("DROP TABLE foobar") --- @@ -202,3 +235,6 @@ box.sql.execute("DROP TABLE foobar") box.sql.execute("DROP TABLE barfoo") --- ... +box.sql.execute("DROP TABLE t1") +--- +... diff --git a/test/sql/persistency.test.lua b/test/sql/persistency.test.lua index fb46c75003..8611bf2f75 100644 --- a/test/sql/persistency.test.lua +++ b/test/sql/persistency.test.lua @@ -51,6 +51,11 @@ box.sql.execute("INSERT INTO barfoo VALUES ('foobar', 1000)") box.sql.execute("CREATE TRIGGER tfoobar AFTER INSERT ON foobar BEGIN INSERT INTO barfoo VALUES ('trigger test', 9999); END") box.sql.execute("SELECT * FROM _trigger"); +-- Many entries +box.sql.execute("CREATE TABLE t1(a,b,c,PRIMARY KEY(b,c));") +box.sql.execute("WITH RECURSIVE cnt(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM cnt WHERE x<1000) INSERT INTO t1 SELECT x, x%40, x/40 FROM cnt;") +box.sql.execute("SELECT a FROM t1 ORDER BY b, a LIMIT 10 OFFSET 20;"); + test_run:cmd('restart server default'); -- prove that trigger survived @@ -75,7 +80,9 @@ box.sql.execute("INSERT INTO barfoo VALUES ('xfoo', 1)") box.sql.execute("SELECT * FROM barfoo") box.sql.execute("SELECT * FROM foobar"); +box.sql.execute("SELECT a FROM t1 ORDER BY b, a LIMIT 10 OFFSET 20;"); -- cleanup box.sql.execute("DROP TABLE foobar") box.sql.execute("DROP TABLE barfoo") +box.sql.execute("DROP TABLE t1") -- GitLab