From f9c65bfc2d1bcb095289423d0c2a30e098326fde Mon Sep 17 00:00:00 2001 From: Bulat Niatshin Date: Tue, 13 Feb 2018 16:28:56 +0300 Subject: [PATCH] sql: fix autoincrement for constraints - 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_NextValue, 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 | 6 +- src/box/sql/opcodes.c | 139 +++++++++++---------- src/box/sql/opcodes.h | 159 ++++++++++++------------ src/box/sql/vdbe.c | 38 ++++++ test/sql/gh-2981-check-autoinc.result | 49 ++++++++ test/sql/gh-2981-check-autoinc.test.lua | 20 +++ 6 files changed, 262 insertions(+), 149 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 b20a47970205..065d1d610ef2 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -34,6 +34,7 @@ * to handle INSERT statements in SQLite. */ #include "sqliteInt.h" +#include "tarantoolInt.h" #include "box/session.h" /* @@ -760,7 +761,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 44818952eca4..cd8752b2110c 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@P3]=r[P1@P3]"), - /* 77 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), - /* 78 */ "SCopy" OpHelp("r[P2]=r[P1]"), - /* 79 */ "IntCopy" OpHelp("r[P2]=r[P1]"), - /* 80 */ "ResultRow" OpHelp("output=r[P1@P2]"), - /* 81 */ "CollSeq" OpHelp(""), - /* 82 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), - /* 83 */ "Function" OpHelp("r[P3]=func(r[P2@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@P3] <-> r[P2@P3]"), - /* 89 */ "Column" OpHelp("r[P3]=PX"), - /* 90 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 91 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@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@cur_frame]= reg[P1@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@P3]=r[P1@P3]"), + /* 78 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), + /* 79 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 80 */ "IntCopy" OpHelp("r[P2]=r[P1]"), + /* 81 */ "ResultRow" OpHelp("output=r[P1@P2]"), + /* 82 */ "CollSeq" OpHelp(""), + /* 83 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), + /* 84 */ "Function" OpHelp("r[P3]=func(r[P2@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@P3] <-> r[P2@P3]"), + /* 90 */ "Column" OpHelp("r[P3]=PX"), + /* 91 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 92 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@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@cur_frame]= reg[P1@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@P3]"), - /* 121 */ "Destroy" OpHelp(""), - /* 122 */ "Clear" OpHelp(""), - /* 123 */ "ResetSorter" OpHelp(""), - /* 124 */ "ParseSchema2" OpHelp("rows=r[P1@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@P5])"), - /* 136 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@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@P3]"), + /* 122 */ "Destroy" OpHelp(""), + /* 123 */ "Clear" OpHelp(""), + /* 124 */ "ResetSorter" OpHelp(""), + /* 125 */ "ParseSchema2" OpHelp("rows=r[P1@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@P5])"), + /* 137 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@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 ccca2379273e..a4e1b82bd7e4 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@P3]=r[P1@P3] */ -#define OP_Copy 77 /* synopsis: r[P2@P3+1]=r[P1@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@P2] */ -#define OP_CollSeq 81 -#define OP_Function0 82 /* synopsis: r[P3]=func(r[P2@P5]) */ -#define OP_Function 83 /* synopsis: r[P3]=func(r[P2@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@P3] <-> r[P2@P3] */ -#define OP_Column 89 /* synopsis: r[P3]=PX */ -#define OP_Affinity 90 /* synopsis: affinity(r[P1@P2]) */ -#define OP_MakeRecord 91 /* synopsis: r[P3]=mkrec(r[P1@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@cur_frame]= reg[P1@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@P3]=r[P1@P3] */ +#define OP_Copy 78 /* synopsis: r[P2@P3+1]=r[P1@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@P2] */ +#define OP_CollSeq 82 +#define OP_Function0 83 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_Function 84 /* synopsis: r[P3]=func(r[P2@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@P3] <-> r[P2@P3] */ +#define OP_Column 90 /* synopsis: r[P3]=PX */ +#define OP_Affinity 91 /* synopsis: affinity(r[P1@P2]) */ +#define OP_MakeRecord 92 /* synopsis: r[P3]=mkrec(r[P1@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@cur_frame]= reg[P1@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@P3] */ -#define OP_Destroy 121 -#define OP_Clear 122 -#define OP_ResetSorter 123 -#define OP_ParseSchema2 124 /* synopsis: rows=r[P1@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@P5]) */ -#define OP_AggStep 136 /* synopsis: accum=r[P3] step(r[P2@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@P3] */ +#define OP_Destroy 122 +#define OP_Clear 123 +#define OP_ResetSorter 124 +#define OP_ParseSchema2 125 /* synopsis: rows=r[P1@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@P5]) */ +#define OP_AggStep 137 /* synopsis: accum=r[P3] step(r[P2@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 b235e7bf639d..d25c295c8ac0 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -45,6 +45,7 @@ #include "vdbeInt.h" #include "tarantoolInt.h" #include "box/sql.h" +#include "box/sequence.h" #include "msgpuck/msgpuck.h" @@ -1141,6 +1142,43 @@ 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 space id 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 000000000000..aaa0785d0e8c --- /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 000000000000..d5a398f123db --- /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")