[patches] [PATCH v2 1/1] sql: fix autoincrement for constraints

Bulat Niatshin niatshin at tarantool.org
Thu Feb 22 02:49:06 MSK 2018


- Compute next autoincrement value before running
  constraints checks and put it to mentioned registers
  instead of NULL, like it was before.
- Implement new opcode OP_NextAutoincValue, which calls
  sequence_next from Tarantool and puts new value to
  necessary register.
- Implement necessary tests.
- Generate new opcodes set.

Closes #2981
---
 src/box/sql/insert.c                    |   5 +-
 src/box/sql/opcodes.c                   | 139 ++++++++++++++--------------
 src/box/sql/opcodes.h                   | 159 ++++++++++++++++----------------
 src/box/sql/vdbe.c                      |  40 +++++++-
 test/sql/gh-2981-check-autoinc.result   |  49 ++++++++++
 test/sql/gh-2981-check-autoinc.test.lua |  20 ++++
 6 files changed, 262 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..0d747b2d1 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,44 @@ 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: {
+	int64_t value;
+	uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(pOp->p1);
+	assert(space_id > 0);
+
+	struct space * space = space_by_id(space_id);
+	if (!space) {
+		rc = SQL_TARANTOOL_ERROR;
+		goto abort_due_to_error;
+	}
+
+	struct sequence * sequence = space->sequence;
+	if (!sequence) {
+		rc = SQL_TARANTOOL_ERROR;
+		goto abort_due_to_error;
+	}
+
+	if (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