[patches] [PATCH V3] sql: fix autoincrement for constraints
Bulat Niatshin
niatshin at tarantool.org
Mon Mar 5 16:13:56 MSK 2018
Autoincrement now is fully supported by Tarantool facilities. However,
during VDBE program execution there were no information about new value
from sequence, instead of new value there was a NULL. This made CHECK
constraints on autoincrement fields working inappropriately.
In this patch:
- Next autoincrement value is computing before
running constraints check and is put to
mentioned registers instead of NULL, like it was before.
- New opcode OP_NextAutoincValue was implemented, which
calls sequence_next from Tarantool and puts new value
to necessary register.
Closes #2981
---
Branch:
https://github.com/tarantool/tarantool/tree/bn/gh-2981-constraints-autoinc
Issue:
https://github.com/tarantool/tarantool/issues/2981
Changes in V3:
- Fixed remarks as per second review by Nikita
- Rebased branch to current 2.0 state
Changes in V2:
- Fixed remarks as per first review by Nikita
src/box/sql/insert.c | 5 +-
src/box/sql/opcodes.c | 139 ++++++++++++++--------------
src/box/sql/opcodes.h | 159 ++++++++++++++++----------------
src/box/sql/vdbe.c | 36 +++++++-
test/sql/gh-2981-check-autoinc.result | 49 ++++++++++
test/sql/gh-2981-check-autoinc.test.lua | 20 ++++
6 files changed, 258 insertions(+), 150 deletions(-)
create mode 100644 test/sql/gh-2981-check-autoinc.result
create mode 100644 test/sql/gh-2981-check-autoinc.test.lua
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index b20a47970..4a556b558 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -760,7 +760,10 @@ sqlite3Insert(Parse * pParse, /* Parser context */
if (j < 0 || nColumn == 0
|| (pColumn && j >= pColumn->nId)) {
if (i == pTab->iAutoIncPKey) {
- sqlite3VdbeAddOp2(v, OP_Null, 0, iRegStore);
+ sqlite3VdbeAddOp2(v,
+ OP_NextAutoincValue,
+ pTab->tnum,
+ iRegStore);
continue;
}
sqlite3ExprCodeFactorable(pParse,
diff --git a/src/box/sql/opcodes.c b/src/box/sql/opcodes.c
index 44818952e..cd8752b21 100644
--- a/src/box/sql/opcodes.c
+++ b/src/box/sql/opcodes.c
@@ -82,77 +82,78 @@ const char *sqlite3OpcodeName(int i){
/* 68 */ "Bool" OpHelp("r[P2]=P1"),
/* 69 */ "Int64" OpHelp("r[P2]=P4"),
/* 70 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
- /* 71 */ "Null" OpHelp("r[P2..P3]=NULL"),
- /* 72 */ "SoftNull" OpHelp("r[P1]=NULL"),
- /* 73 */ "Blob" OpHelp("r[P2]=P4 (len=P1, subtype=P3)"),
- /* 74 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
+ /* 71 */ "NextAutoincValue" OpHelp("r[P2] = next value from space sequence, which pageno is r[P1]"),
+ /* 72 */ "Null" OpHelp("r[P2..P3]=NULL"),
+ /* 73 */ "SoftNull" OpHelp("r[P1]=NULL"),
+ /* 74 */ "Blob" OpHelp("r[P2]=P4 (len=P1, subtype=P3)"),
/* 75 */ "String8" OpHelp("r[P2]='P4'"),
- /* 76 */ "Move" OpHelp("r[P2 at P3]=r[P1 at P3]"),
- /* 77 */ "Copy" OpHelp("r[P2 at P3+1]=r[P1 at P3+1]"),
- /* 78 */ "SCopy" OpHelp("r[P2]=r[P1]"),
- /* 79 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
- /* 80 */ "ResultRow" OpHelp("output=r[P1 at P2]"),
- /* 81 */ "CollSeq" OpHelp(""),
- /* 82 */ "Function0" OpHelp("r[P3]=func(r[P2 at P5])"),
- /* 83 */ "Function" OpHelp("r[P3]=func(r[P2 at P5])"),
- /* 84 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
- /* 85 */ "RealAffinity" OpHelp(""),
- /* 86 */ "Cast" OpHelp("affinity(r[P1])"),
- /* 87 */ "Permutation" OpHelp(""),
- /* 88 */ "Compare" OpHelp("r[P1 at P3] <-> r[P2 at P3]"),
- /* 89 */ "Column" OpHelp("r[P3]=PX"),
- /* 90 */ "Affinity" OpHelp("affinity(r[P1 at P2])"),
- /* 91 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1 at P2])"),
- /* 92 */ "Count" OpHelp("r[P2]=count()"),
- /* 93 */ "FkCheckCommit" OpHelp(""),
- /* 94 */ "TTransaction" OpHelp(""),
- /* 95 */ "ReadCookie" OpHelp(""),
- /* 96 */ "SetCookie" OpHelp(""),
- /* 97 */ "ReopenIdx" OpHelp("root=P2"),
- /* 98 */ "OpenRead" OpHelp("root=P2"),
- /* 99 */ "OpenWrite" OpHelp("root=P2"),
- /* 100 */ "OpenTEphemeral" OpHelp("nColumn = P2"),
- /* 101 */ "SorterOpen" OpHelp(""),
- /* 102 */ "SequenceTest" OpHelp("if (cursor[P1].ctr++) pc = P2"),
- /* 103 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
- /* 104 */ "Close" OpHelp(""),
- /* 105 */ "ColumnsUsed" OpHelp(""),
- /* 106 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
- /* 107 */ "NextId" OpHelp("r[P3]=get_max(space_index[P1]{Column[P2]})"),
- /* 108 */ "NextIdEphemeral" OpHelp("r[P3]=get_max(space_index[P1]{Column[P2]})"),
- /* 109 */ "FCopy" OpHelp("reg[P2 at cur_frame]= reg[P1 at root_frame(OPFLAG_SAME_FRAME)]"),
- /* 110 */ "Delete" OpHelp(""),
- /* 111 */ "ResetCount" OpHelp(""),
- /* 112 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
- /* 113 */ "SorterData" OpHelp("r[P2]=data"),
- /* 114 */ "RowData" OpHelp("r[P2]=data"),
+ /* 76 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
+ /* 77 */ "Move" OpHelp("r[P2 at P3]=r[P1 at P3]"),
+ /* 78 */ "Copy" OpHelp("r[P2 at P3+1]=r[P1 at P3+1]"),
+ /* 79 */ "SCopy" OpHelp("r[P2]=r[P1]"),
+ /* 80 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
+ /* 81 */ "ResultRow" OpHelp("output=r[P1 at P2]"),
+ /* 82 */ "CollSeq" OpHelp(""),
+ /* 83 */ "Function0" OpHelp("r[P3]=func(r[P2 at P5])"),
+ /* 84 */ "Function" OpHelp("r[P3]=func(r[P2 at P5])"),
+ /* 85 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
+ /* 86 */ "RealAffinity" OpHelp(""),
+ /* 87 */ "Cast" OpHelp("affinity(r[P1])"),
+ /* 88 */ "Permutation" OpHelp(""),
+ /* 89 */ "Compare" OpHelp("r[P1 at P3] <-> r[P2 at P3]"),
+ /* 90 */ "Column" OpHelp("r[P3]=PX"),
+ /* 91 */ "Affinity" OpHelp("affinity(r[P1 at P2])"),
+ /* 92 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1 at P2])"),
+ /* 93 */ "Count" OpHelp("r[P2]=count()"),
+ /* 94 */ "FkCheckCommit" OpHelp(""),
+ /* 95 */ "TTransaction" OpHelp(""),
+ /* 96 */ "ReadCookie" OpHelp(""),
+ /* 97 */ "SetCookie" OpHelp(""),
+ /* 98 */ "ReopenIdx" OpHelp("root=P2"),
+ /* 99 */ "OpenRead" OpHelp("root=P2"),
+ /* 100 */ "OpenWrite" OpHelp("root=P2"),
+ /* 101 */ "OpenTEphemeral" OpHelp("nColumn = P2"),
+ /* 102 */ "SorterOpen" OpHelp(""),
+ /* 103 */ "SequenceTest" OpHelp("if (cursor[P1].ctr++) pc = P2"),
+ /* 104 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
+ /* 105 */ "Close" OpHelp(""),
+ /* 106 */ "ColumnsUsed" OpHelp(""),
+ /* 107 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
+ /* 108 */ "NextId" OpHelp("r[P3]=get_max(space_index[P1]{Column[P2]})"),
+ /* 109 */ "NextIdEphemeral" OpHelp("r[P3]=get_max(space_index[P1]{Column[P2]})"),
+ /* 110 */ "FCopy" OpHelp("reg[P2 at cur_frame]= reg[P1 at root_frame(OPFLAG_SAME_FRAME)]"),
+ /* 111 */ "Delete" OpHelp(""),
+ /* 112 */ "ResetCount" OpHelp(""),
+ /* 113 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
+ /* 114 */ "SorterData" OpHelp("r[P2]=data"),
/* 115 */ "Real" OpHelp("r[P2]=P4"),
- /* 116 */ "NullRow" OpHelp(""),
- /* 117 */ "SorterInsert" OpHelp("key=r[P2]"),
- /* 118 */ "IdxReplace" OpHelp("key=r[P2]"),
- /* 119 */ "IdxInsert" OpHelp("key=r[P2]"),
- /* 120 */ "IdxDelete" OpHelp("key=r[P2 at P3]"),
- /* 121 */ "Destroy" OpHelp(""),
- /* 122 */ "Clear" OpHelp(""),
- /* 123 */ "ResetSorter" OpHelp(""),
- /* 124 */ "ParseSchema2" OpHelp("rows=r[P1 at P2]"),
- /* 125 */ "ParseSchema3" OpHelp("name=r[P1] sql=r[P1+1]"),
- /* 126 */ "RenameTable" OpHelp("P1 = root, P4 = name"),
- /* 127 */ "LoadAnalysis" OpHelp(""),
- /* 128 */ "DropTable" OpHelp(""),
- /* 129 */ "DropIndex" OpHelp(""),
- /* 130 */ "DropTrigger" OpHelp(""),
- /* 131 */ "Param" OpHelp(""),
- /* 132 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
- /* 133 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
- /* 134 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
- /* 135 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2 at P5])"),
- /* 136 */ "AggStep" OpHelp("accum=r[P3] step(r[P2 at P5])"),
- /* 137 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
- /* 138 */ "Expire" OpHelp(""),
- /* 139 */ "IncMaxid" OpHelp(""),
- /* 140 */ "Noop" OpHelp(""),
- /* 141 */ "Explain" OpHelp(""),
+ /* 116 */ "RowData" OpHelp("r[P2]=data"),
+ /* 117 */ "NullRow" OpHelp(""),
+ /* 118 */ "SorterInsert" OpHelp("key=r[P2]"),
+ /* 119 */ "IdxReplace" OpHelp("key=r[P2]"),
+ /* 120 */ "IdxInsert" OpHelp("key=r[P2]"),
+ /* 121 */ "IdxDelete" OpHelp("key=r[P2 at P3]"),
+ /* 122 */ "Destroy" OpHelp(""),
+ /* 123 */ "Clear" OpHelp(""),
+ /* 124 */ "ResetSorter" OpHelp(""),
+ /* 125 */ "ParseSchema2" OpHelp("rows=r[P1 at P2]"),
+ /* 126 */ "ParseSchema3" OpHelp("name=r[P1] sql=r[P1+1]"),
+ /* 127 */ "RenameTable" OpHelp("P1 = root, P4 = name"),
+ /* 128 */ "LoadAnalysis" OpHelp(""),
+ /* 129 */ "DropTable" OpHelp(""),
+ /* 130 */ "DropIndex" OpHelp(""),
+ /* 131 */ "DropTrigger" OpHelp(""),
+ /* 132 */ "Param" OpHelp(""),
+ /* 133 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
+ /* 134 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
+ /* 135 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
+ /* 136 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2 at P5])"),
+ /* 137 */ "AggStep" OpHelp("accum=r[P3] step(r[P2 at P5])"),
+ /* 138 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
+ /* 139 */ "Expire" OpHelp(""),
+ /* 140 */ "IncMaxid" OpHelp(""),
+ /* 141 */ "Noop" OpHelp(""),
+ /* 142 */ "Explain" OpHelp(""),
};
return azName[i];
}
diff --git a/src/box/sql/opcodes.h b/src/box/sql/opcodes.h
index ccca23792..a4e1b82bd 100644
--- a/src/box/sql/opcodes.h
+++ b/src/box/sql/opcodes.h
@@ -71,77 +71,78 @@
#define OP_Bool 68 /* synopsis: r[P2]=P1 */
#define OP_Int64 69 /* synopsis: r[P2]=P4 */
#define OP_String 70 /* synopsis: r[P2]='P4' (len=P1) */
-#define OP_Null 71 /* synopsis: r[P2..P3]=NULL */
-#define OP_SoftNull 72 /* synopsis: r[P1]=NULL */
-#define OP_Blob 73 /* synopsis: r[P2]=P4 (len=P1, subtype=P3) */
-#define OP_Variable 74 /* synopsis: r[P2]=parameter(P1,P4) */
+#define OP_NextAutoincValue 71 /* synopsis: r[P2] = next value from space sequence, which pageno is r[P1] */
+#define OP_Null 72 /* synopsis: r[P2..P3]=NULL */
+#define OP_SoftNull 73 /* synopsis: r[P1]=NULL */
+#define OP_Blob 74 /* synopsis: r[P2]=P4 (len=P1, subtype=P3) */
#define OP_String8 75 /* same as TK_STRING, synopsis: r[P2]='P4' */
-#define OP_Move 76 /* synopsis: r[P2 at P3]=r[P1 at P3] */
-#define OP_Copy 77 /* synopsis: r[P2 at P3+1]=r[P1 at P3+1] */
-#define OP_SCopy 78 /* synopsis: r[P2]=r[P1] */
-#define OP_IntCopy 79 /* synopsis: r[P2]=r[P1] */
-#define OP_ResultRow 80 /* synopsis: output=r[P1 at P2] */
-#define OP_CollSeq 81
-#define OP_Function0 82 /* synopsis: r[P3]=func(r[P2 at P5]) */
-#define OP_Function 83 /* synopsis: r[P3]=func(r[P2 at P5]) */
-#define OP_AddImm 84 /* synopsis: r[P1]=r[P1]+P2 */
-#define OP_RealAffinity 85
-#define OP_Cast 86 /* synopsis: affinity(r[P1]) */
-#define OP_Permutation 87
-#define OP_Compare 88 /* synopsis: r[P1 at P3] <-> r[P2 at P3] */
-#define OP_Column 89 /* synopsis: r[P3]=PX */
-#define OP_Affinity 90 /* synopsis: affinity(r[P1 at P2]) */
-#define OP_MakeRecord 91 /* synopsis: r[P3]=mkrec(r[P1 at P2]) */
-#define OP_Count 92 /* synopsis: r[P2]=count() */
-#define OP_FkCheckCommit 93
-#define OP_TTransaction 94
-#define OP_ReadCookie 95
-#define OP_SetCookie 96
-#define OP_ReopenIdx 97 /* synopsis: root=P2 */
-#define OP_OpenRead 98 /* synopsis: root=P2 */
-#define OP_OpenWrite 99 /* synopsis: root=P2 */
-#define OP_OpenTEphemeral 100 /* synopsis: nColumn = P2 */
-#define OP_SorterOpen 101
-#define OP_SequenceTest 102 /* synopsis: if (cursor[P1].ctr++) pc = P2 */
-#define OP_OpenPseudo 103 /* synopsis: P3 columns in r[P2] */
-#define OP_Close 104
-#define OP_ColumnsUsed 105
-#define OP_Sequence 106 /* synopsis: r[P2]=cursor[P1].ctr++ */
-#define OP_NextId 107 /* synopsis: r[P3]=get_max(space_index[P1]{Column[P2]}) */
-#define OP_NextIdEphemeral 108 /* synopsis: r[P3]=get_max(space_index[P1]{Column[P2]}) */
-#define OP_FCopy 109 /* synopsis: reg[P2 at cur_frame]= reg[P1 at root_frame(OPFLAG_SAME_FRAME)] */
-#define OP_Delete 110
-#define OP_ResetCount 111
-#define OP_SorterCompare 112 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
-#define OP_SorterData 113 /* synopsis: r[P2]=data */
-#define OP_RowData 114 /* synopsis: r[P2]=data */
+#define OP_Variable 76 /* synopsis: r[P2]=parameter(P1,P4) */
+#define OP_Move 77 /* synopsis: r[P2 at P3]=r[P1 at P3] */
+#define OP_Copy 78 /* synopsis: r[P2 at P3+1]=r[P1 at P3+1] */
+#define OP_SCopy 79 /* synopsis: r[P2]=r[P1] */
+#define OP_IntCopy 80 /* synopsis: r[P2]=r[P1] */
+#define OP_ResultRow 81 /* synopsis: output=r[P1 at P2] */
+#define OP_CollSeq 82
+#define OP_Function0 83 /* synopsis: r[P3]=func(r[P2 at P5]) */
+#define OP_Function 84 /* synopsis: r[P3]=func(r[P2 at P5]) */
+#define OP_AddImm 85 /* synopsis: r[P1]=r[P1]+P2 */
+#define OP_RealAffinity 86
+#define OP_Cast 87 /* synopsis: affinity(r[P1]) */
+#define OP_Permutation 88
+#define OP_Compare 89 /* synopsis: r[P1 at P3] <-> r[P2 at P3] */
+#define OP_Column 90 /* synopsis: r[P3]=PX */
+#define OP_Affinity 91 /* synopsis: affinity(r[P1 at P2]) */
+#define OP_MakeRecord 92 /* synopsis: r[P3]=mkrec(r[P1 at P2]) */
+#define OP_Count 93 /* synopsis: r[P2]=count() */
+#define OP_FkCheckCommit 94
+#define OP_TTransaction 95
+#define OP_ReadCookie 96
+#define OP_SetCookie 97
+#define OP_ReopenIdx 98 /* synopsis: root=P2 */
+#define OP_OpenRead 99 /* synopsis: root=P2 */
+#define OP_OpenWrite 100 /* synopsis: root=P2 */
+#define OP_OpenTEphemeral 101 /* synopsis: nColumn = P2 */
+#define OP_SorterOpen 102
+#define OP_SequenceTest 103 /* synopsis: if (cursor[P1].ctr++) pc = P2 */
+#define OP_OpenPseudo 104 /* synopsis: P3 columns in r[P2] */
+#define OP_Close 105
+#define OP_ColumnsUsed 106
+#define OP_Sequence 107 /* synopsis: r[P2]=cursor[P1].ctr++ */
+#define OP_NextId 108 /* synopsis: r[P3]=get_max(space_index[P1]{Column[P2]}) */
+#define OP_NextIdEphemeral 109 /* synopsis: r[P3]=get_max(space_index[P1]{Column[P2]}) */
+#define OP_FCopy 110 /* synopsis: reg[P2 at cur_frame]= reg[P1 at root_frame(OPFLAG_SAME_FRAME)] */
+#define OP_Delete 111
+#define OP_ResetCount 112
+#define OP_SorterCompare 113 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
+#define OP_SorterData 114 /* synopsis: r[P2]=data */
#define OP_Real 115 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
-#define OP_NullRow 116
-#define OP_SorterInsert 117 /* synopsis: key=r[P2] */
-#define OP_IdxReplace 118 /* synopsis: key=r[P2] */
-#define OP_IdxInsert 119 /* synopsis: key=r[P2] */
-#define OP_IdxDelete 120 /* synopsis: key=r[P2 at P3] */
-#define OP_Destroy 121
-#define OP_Clear 122
-#define OP_ResetSorter 123
-#define OP_ParseSchema2 124 /* synopsis: rows=r[P1 at P2] */
-#define OP_ParseSchema3 125 /* synopsis: name=r[P1] sql=r[P1+1] */
-#define OP_RenameTable 126 /* synopsis: P1 = root, P4 = name */
-#define OP_LoadAnalysis 127
-#define OP_DropTable 128
-#define OP_DropIndex 129
-#define OP_DropTrigger 130
-#define OP_Param 131
-#define OP_FkCounter 132 /* synopsis: fkctr[P1]+=P2 */
-#define OP_MemMax 133 /* synopsis: r[P1]=max(r[P1],r[P2]) */
-#define OP_OffsetLimit 134 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
-#define OP_AggStep0 135 /* synopsis: accum=r[P3] step(r[P2 at P5]) */
-#define OP_AggStep 136 /* synopsis: accum=r[P3] step(r[P2 at P5]) */
-#define OP_AggFinal 137 /* synopsis: accum=r[P1] N=P2 */
-#define OP_Expire 138
-#define OP_IncMaxid 139
-#define OP_Noop 140
-#define OP_Explain 141
+#define OP_RowData 116 /* synopsis: r[P2]=data */
+#define OP_NullRow 117
+#define OP_SorterInsert 118 /* synopsis: key=r[P2] */
+#define OP_IdxReplace 119 /* synopsis: key=r[P2] */
+#define OP_IdxInsert 120 /* synopsis: key=r[P2] */
+#define OP_IdxDelete 121 /* synopsis: key=r[P2 at P3] */
+#define OP_Destroy 122
+#define OP_Clear 123
+#define OP_ResetSorter 124
+#define OP_ParseSchema2 125 /* synopsis: rows=r[P1 at P2] */
+#define OP_ParseSchema3 126 /* synopsis: name=r[P1] sql=r[P1+1] */
+#define OP_RenameTable 127 /* synopsis: P1 = root, P4 = name */
+#define OP_LoadAnalysis 128
+#define OP_DropTable 129
+#define OP_DropIndex 130
+#define OP_DropTrigger 131
+#define OP_Param 132
+#define OP_FkCounter 133 /* synopsis: fkctr[P1]+=P2 */
+#define OP_MemMax 134 /* synopsis: r[P1]=max(r[P1],r[P2]) */
+#define OP_OffsetLimit 135 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
+#define OP_AggStep0 136 /* synopsis: accum=r[P3] step(r[P2 at P5]) */
+#define OP_AggStep 137 /* synopsis: accum=r[P3] step(r[P2 at P5]) */
+#define OP_AggFinal 138 /* synopsis: accum=r[P1] N=P2 */
+#define OP_Expire 139
+#define OP_IncMaxid 140
+#define OP_Noop 141
+#define OP_Explain 142
/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
@@ -162,16 +163,16 @@
/* 40 */ 0x03, 0x03, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\
/* 48 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
/* 56 */ 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x01, 0x02,\
-/* 64 */ 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10,\
-/* 72 */ 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10,\
-/* 80 */ 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00,\
-/* 88 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,\
-/* 96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 104 */ 0x00, 0x00, 0x10, 0x20, 0x00, 0x10, 0x00, 0x00,\
-/* 112 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00, 0x04,\
-/* 120 */ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 128 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x1a, 0x00,\
-/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}
+/* 64 */ 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00,\
+/* 72 */ 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10,\
+/* 80 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02,\
+/* 88 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\
+/* 96 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 104 */ 0x00, 0x00, 0x00, 0x10, 0x20, 0x00, 0x10, 0x00,\
+/* 112 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04, 0x00,\
+/* 120 */ 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x1a,\
+/* 136 */ 0x00, 0x00, 0x00, 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/vdbe.c b/src/box/sql/vdbe.c
index b235e7bf6..39f925432 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -44,12 +44,12 @@
#include "sqliteInt.h"
#include "vdbeInt.h"
#include "tarantoolInt.h"
-#include "box/sql.h"
#include "msgpuck/msgpuck.h"
#include "box/schema.h"
#include "box/space.h"
+#include "box/sequence.h"
/*
* Invoke this macro on memory cells just prior to changing the
@@ -1141,6 +1141,40 @@ case OP_String: { /* out2 */
break;
}
+/* Opcode: NextAutoincValue P1 P2 * * *
+ * Synopsis: r[P2] = next value from space sequence, which pageno is r[P1]
+ *
+ * Get next value from space sequence, which pageno is written into register
+ * P1, write this value into register P2. If space doesn't exists (invalid
+ * space_id or something else), raise an error. If space with
+ * specified space_id doesn't have attached sequence, also raise an error.
+ */
+case OP_NextAutoincValue: {
+ assert(pOp->p1 > 0);
+ assert(pOp->p2 > 0);
+
+ int64_t value;
+ uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(pOp->p1);
+
+ struct space *space = space_by_id(space_id);
+ if (space == NULL) {
+ rc = SQL_TARANTOOL_ERROR;
+ goto abort_due_to_error;
+ }
+
+ struct sequence *sequence = space->sequence;
+ if (sequence == NULL || sequence_next(sequence, &value) != 0) {
+ rc = SQL_TARANTOOL_ERROR;
+ goto abort_due_to_error;
+ }
+
+ pOut = out2Prerelease(p, pOp);
+ pOut->flags = MEM_Int;
+ pOut->u.i = value;
+
+ break;
+}
+
/* Opcode: Null P1 P2 P3 * *
* Synopsis: r[P2..P3]=NULL
*
diff --git a/test/sql/gh-2981-check-autoinc.result b/test/sql/gh-2981-check-autoinc.result
new file mode 100644
index 000000000..aaa0785d0
--- /dev/null
+++ b/test/sql/gh-2981-check-autoinc.result
@@ -0,0 +1,49 @@
+box.cfg{}
+---
+...
+box.sql.execute("CREATE TABLE t1 (s1 INTEGER PRIMARY KEY AUTOINCREMENT, s2 INTEGER, CHECK (s1 <> 19));");
+---
+...
+box.sql.execute("CREATE TABLE t2 (s1 INTEGER PRIMARY KEY AUTOINCREMENT, s2 INTEGER, CHECK (s1 <> 19 AND s1 <> 25));");
+---
+...
+box.sql.execute("CREATE TABLE t3 (s1 INTEGER PRIMARY KEY AUTOINCREMENT, s2 INTEGER, CHECK (s1 < 10));");
+---
+...
+box.sql.execute("insert into t1 values (18, null);")
+---
+...
+box.sql.execute("insert into t1(s2) values (null);")
+---
+- error: 'CHECK constraint failed: T1'
+...
+box.sql.execute("insert into t2 values (18, null);")
+---
+...
+box.sql.execute("insert into t2(s2) values (null);")
+---
+- error: 'CHECK constraint failed: T2'
+...
+box.sql.execute("insert into t2 values (24, null);")
+---
+...
+box.sql.execute("insert into t2(s2) values (null);")
+---
+- error: 'CHECK constraint failed: T2'
+...
+box.sql.execute("insert into t3 values (9, null)")
+---
+...
+box.sql.execute("insert into t3(s2) values (null)")
+---
+- error: 'CHECK constraint failed: T3'
+...
+box.sql.execute("DROP TABLE t1")
+---
+...
+box.sql.execute("DROP TABLE t2")
+---
+...
+box.sql.execute("DROP TABLE t3")
+---
+...
diff --git a/test/sql/gh-2981-check-autoinc.test.lua b/test/sql/gh-2981-check-autoinc.test.lua
new file mode 100644
index 000000000..d5a398f12
--- /dev/null
+++ b/test/sql/gh-2981-check-autoinc.test.lua
@@ -0,0 +1,20 @@
+box.cfg{}
+
+box.sql.execute("CREATE TABLE t1 (s1 INTEGER PRIMARY KEY AUTOINCREMENT, s2 INTEGER, CHECK (s1 <> 19));");
+box.sql.execute("CREATE TABLE t2 (s1 INTEGER PRIMARY KEY AUTOINCREMENT, s2 INTEGER, CHECK (s1 <> 19 AND s1 <> 25));");
+box.sql.execute("CREATE TABLE t3 (s1 INTEGER PRIMARY KEY AUTOINCREMENT, s2 INTEGER, CHECK (s1 < 10));");
+
+box.sql.execute("insert into t1 values (18, null);")
+box.sql.execute("insert into t1(s2) values (null);")
+
+box.sql.execute("insert into t2 values (18, null);")
+box.sql.execute("insert into t2(s2) values (null);")
+box.sql.execute("insert into t2 values (24, null);")
+box.sql.execute("insert into t2(s2) values (null);")
+
+box.sql.execute("insert into t3 values (9, null)")
+box.sql.execute("insert into t3(s2) values (null)")
+
+box.sql.execute("DROP TABLE t1")
+box.sql.execute("DROP TABLE t2")
+box.sql.execute("DROP TABLE t3")
--
2.14.1
More information about the Tarantool-patches
mailing list