From 10e4b2b092dd8e76a37f12ccc99f9539756ed427 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 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 --- src/box/sql/insert.c | 5 +- src/box/sql/opcodes.c | 135 +++++++++++---------- src/box/sql/opcodes.h | 155 ++++++++++++------------ src/box/sql/vdbe.c | 36 +++++- test/sql/gh-2981-check-autoinc.result | 49 ++++++++ test/sql/gh-2981-check-autoinc.test.lua | 21 ++++ 6 files changed, 255 insertions(+), 146 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 54fcca5c93b6..431f5af881a2 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -741,7 +741,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 53603037d338..cc1d6023fefa 100644 --- a/src/box/sql/opcodes.c +++ b/src/box/sql/opcodes.c @@ -79,75 +79,76 @@ const char *sqlite3OpcodeName(int i){ /* 65 */ "Bool" OpHelp("r[P2]=P1"), /* 66 */ "Int64" OpHelp("r[P2]=P4"), /* 67 */ "String" OpHelp("r[P2]='P4' (len=P1)"), - /* 68 */ "Null" OpHelp("r[P2..P3]=NULL"), - /* 69 */ "SoftNull" OpHelp("r[P1]=NULL"), - /* 70 */ "Blob" OpHelp("r[P2]=P4 (len=P1, subtype=P3)"), - /* 71 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), - /* 72 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), - /* 73 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), - /* 74 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 68 */ "NextAutoincValue" OpHelp("r[P2] = next value from space sequence, which pageno is r[P1]"), + /* 69 */ "Null" OpHelp("r[P2..P3]=NULL"), + /* 70 */ "SoftNull" OpHelp("r[P1]=NULL"), + /* 71 */ "Blob" OpHelp("r[P2]=P4 (len=P1, subtype=P3)"), + /* 72 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"), + /* 73 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), + /* 74 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), /* 75 */ "String8" OpHelp("r[P2]='P4'"), - /* 76 */ "IntCopy" OpHelp("r[P2]=r[P1]"), - /* 77 */ "ResultRow" OpHelp("output=r[P1@P2]"), - /* 78 */ "CollSeq" OpHelp(""), - /* 79 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), - /* 80 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), - /* 81 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), - /* 82 */ "RealAffinity" OpHelp(""), - /* 83 */ "Cast" OpHelp("affinity(r[P1])"), - /* 84 */ "Permutation" OpHelp(""), - /* 85 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), - /* 86 */ "Column" OpHelp("r[P3]=PX"), - /* 87 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 88 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), - /* 89 */ "Count" OpHelp("r[P2]=count()"), - /* 90 */ "FkCheckCommit" OpHelp(""), - /* 91 */ "TTransaction" OpHelp(""), - /* 92 */ "ReadCookie" OpHelp(""), - /* 93 */ "SetCookie" OpHelp(""), - /* 94 */ "ReopenIdx" OpHelp("root=P2"), - /* 95 */ "OpenRead" OpHelp("root=P2"), - /* 96 */ "OpenWrite" OpHelp("root=P2"), - /* 97 */ "OpenTEphemeral" OpHelp("nColumn = P2"), - /* 98 */ "SorterOpen" OpHelp(""), - /* 99 */ "SequenceTest" OpHelp("if (cursor[P1].ctr++) pc = P2"), - /* 100 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), - /* 101 */ "Close" OpHelp(""), - /* 102 */ "ColumnsUsed" OpHelp(""), - /* 103 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), - /* 104 */ "NextId" OpHelp("r[P3]=get_max(space_index[P1]{Column[P2]})"), - /* 105 */ "NextIdEphemeral" OpHelp("r[P3]=get_max(space_index[P1]{Column[P2]})"), - /* 106 */ "FCopy" OpHelp("reg[P2@cur_frame]= reg[P1@root_frame(OPFLAG_SAME_FRAME)]"), - /* 107 */ "Delete" OpHelp(""), - /* 108 */ "ResetCount" OpHelp(""), - /* 109 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), - /* 110 */ "SorterData" OpHelp("r[P2]=data"), - /* 111 */ "RowData" OpHelp("r[P2]=data"), - /* 112 */ "NullRow" OpHelp(""), - /* 113 */ "SorterInsert" OpHelp("key=r[P2]"), - /* 114 */ "IdxReplace" OpHelp("key=r[P2]"), + /* 76 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 77 */ "IntCopy" OpHelp("r[P2]=r[P1]"), + /* 78 */ "ResultRow" OpHelp("output=r[P1@P2]"), + /* 79 */ "CollSeq" OpHelp(""), + /* 80 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"), + /* 81 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"), + /* 82 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), + /* 83 */ "RealAffinity" OpHelp(""), + /* 84 */ "Cast" OpHelp("affinity(r[P1])"), + /* 85 */ "Permutation" OpHelp(""), + /* 86 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), + /* 87 */ "Column" OpHelp("r[P3]=PX"), + /* 88 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 89 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 90 */ "Count" OpHelp("r[P2]=count()"), + /* 91 */ "FkCheckCommit" OpHelp(""), + /* 92 */ "TTransaction" OpHelp(""), + /* 93 */ "ReadCookie" OpHelp(""), + /* 94 */ "SetCookie" OpHelp(""), + /* 95 */ "ReopenIdx" OpHelp("root=P2"), + /* 96 */ "OpenRead" OpHelp("root=P2"), + /* 97 */ "OpenWrite" OpHelp("root=P2"), + /* 98 */ "OpenTEphemeral" OpHelp("nColumn = P2"), + /* 99 */ "SorterOpen" OpHelp(""), + /* 100 */ "SequenceTest" OpHelp("if (cursor[P1].ctr++) pc = P2"), + /* 101 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 102 */ "Close" OpHelp(""), + /* 103 */ "ColumnsUsed" OpHelp(""), + /* 104 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"), + /* 105 */ "NextId" OpHelp("r[P3]=get_max(space_index[P1]{Column[P2]})"), + /* 106 */ "NextIdEphemeral" OpHelp("r[P3]=get_max(space_index[P1]{Column[P2]})"), + /* 107 */ "FCopy" OpHelp("reg[P2@cur_frame]= reg[P1@root_frame(OPFLAG_SAME_FRAME)]"), + /* 108 */ "Delete" OpHelp(""), + /* 109 */ "ResetCount" OpHelp(""), + /* 110 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"), + /* 111 */ "SorterData" OpHelp("r[P2]=data"), + /* 112 */ "RowData" OpHelp("r[P2]=data"), + /* 113 */ "NullRow" OpHelp(""), + /* 114 */ "SorterInsert" OpHelp("key=r[P2]"), /* 115 */ "Real" OpHelp("r[P2]=P4"), - /* 116 */ "IdxInsert" OpHelp("key=r[P2]"), - /* 117 */ "IdxDelete" OpHelp("key=r[P2@P3]"), - /* 118 */ "Clear" OpHelp(""), - /* 119 */ "ResetSorter" OpHelp(""), - /* 120 */ "ParseSchema2" OpHelp("rows=r[P1@P2]"), - /* 121 */ "ParseSchema3" OpHelp("name=r[P1] sql=r[P1+1]"), - /* 122 */ "RenameTable" OpHelp("P1 = root, P4 = name"), - /* 123 */ "LoadAnalysis" OpHelp(""), - /* 124 */ "DropTable" OpHelp(""), - /* 125 */ "DropIndex" OpHelp(""), - /* 126 */ "DropTrigger" OpHelp(""), - /* 127 */ "Param" OpHelp(""), - /* 128 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), - /* 129 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), - /* 130 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 131 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 132 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 133 */ "Expire" OpHelp(""), - /* 134 */ "IncMaxid" OpHelp(""), - /* 135 */ "Noop" OpHelp(""), - /* 136 */ "Explain" OpHelp(""), + /* 116 */ "IdxReplace" OpHelp("key=r[P2]"), + /* 117 */ "IdxInsert" OpHelp("key=r[P2]"), + /* 118 */ "IdxDelete" OpHelp("key=r[P2@P3]"), + /* 119 */ "Clear" OpHelp(""), + /* 120 */ "ResetSorter" OpHelp(""), + /* 121 */ "ParseSchema2" OpHelp("rows=r[P1@P2]"), + /* 122 */ "ParseSchema3" OpHelp("name=r[P1] sql=r[P1+1]"), + /* 123 */ "RenameTable" OpHelp("P1 = root, P4 = name"), + /* 124 */ "LoadAnalysis" OpHelp(""), + /* 125 */ "DropTable" OpHelp(""), + /* 126 */ "DropIndex" OpHelp(""), + /* 127 */ "DropTrigger" OpHelp(""), + /* 128 */ "Param" OpHelp(""), + /* 129 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 130 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 131 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 132 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 133 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 134 */ "Expire" OpHelp(""), + /* 135 */ "IncMaxid" OpHelp(""), + /* 136 */ "Noop" OpHelp(""), + /* 137 */ "Explain" OpHelp(""), }; return azName[i]; } diff --git a/src/box/sql/opcodes.h b/src/box/sql/opcodes.h index 1fbb6b690699..86ea6cf94a7d 100644 --- a/src/box/sql/opcodes.h +++ b/src/box/sql/opcodes.h @@ -68,75 +68,76 @@ #define OP_Bool 65 /* synopsis: r[P2]=P1 */ #define OP_Int64 66 /* synopsis: r[P2]=P4 */ #define OP_String 67 /* synopsis: r[P2]='P4' (len=P1) */ -#define OP_Null 68 /* synopsis: r[P2..P3]=NULL */ -#define OP_SoftNull 69 /* synopsis: r[P1]=NULL */ -#define OP_Blob 70 /* synopsis: r[P2]=P4 (len=P1, subtype=P3) */ -#define OP_Variable 71 /* synopsis: r[P2]=parameter(P1,P4) */ -#define OP_Move 72 /* synopsis: r[P2@P3]=r[P1@P3] */ -#define OP_Copy 73 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ -#define OP_SCopy 74 /* synopsis: r[P2]=r[P1] */ +#define OP_NextAutoincValue 68 /* synopsis: r[P2] = next value from space sequence, which pageno is r[P1] */ +#define OP_Null 69 /* synopsis: r[P2..P3]=NULL */ +#define OP_SoftNull 70 /* synopsis: r[P1]=NULL */ +#define OP_Blob 71 /* synopsis: r[P2]=P4 (len=P1, subtype=P3) */ +#define OP_Variable 72 /* synopsis: r[P2]=parameter(P1,P4) */ +#define OP_Move 73 /* synopsis: r[P2@P3]=r[P1@P3] */ +#define OP_Copy 74 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ #define OP_String8 75 /* same as TK_STRING, synopsis: r[P2]='P4' */ -#define OP_IntCopy 76 /* synopsis: r[P2]=r[P1] */ -#define OP_ResultRow 77 /* synopsis: output=r[P1@P2] */ -#define OP_CollSeq 78 -#define OP_Function0 79 /* synopsis: r[P3]=func(r[P2@P5]) */ -#define OP_Function 80 /* synopsis: r[P3]=func(r[P2@P5]) */ -#define OP_AddImm 81 /* synopsis: r[P1]=r[P1]+P2 */ -#define OP_RealAffinity 82 -#define OP_Cast 83 /* synopsis: affinity(r[P1]) */ -#define OP_Permutation 84 -#define OP_Compare 85 /* synopsis: r[P1@P3] <-> r[P2@P3] */ -#define OP_Column 86 /* synopsis: r[P3]=PX */ -#define OP_Affinity 87 /* synopsis: affinity(r[P1@P2]) */ -#define OP_MakeRecord 88 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ -#define OP_Count 89 /* synopsis: r[P2]=count() */ -#define OP_FkCheckCommit 90 -#define OP_TTransaction 91 -#define OP_ReadCookie 92 -#define OP_SetCookie 93 -#define OP_ReopenIdx 94 /* synopsis: root=P2 */ -#define OP_OpenRead 95 /* synopsis: root=P2 */ -#define OP_OpenWrite 96 /* synopsis: root=P2 */ -#define OP_OpenTEphemeral 97 /* synopsis: nColumn = P2 */ -#define OP_SorterOpen 98 -#define OP_SequenceTest 99 /* synopsis: if (cursor[P1].ctr++) pc = P2 */ -#define OP_OpenPseudo 100 /* synopsis: P3 columns in r[P2] */ -#define OP_Close 101 -#define OP_ColumnsUsed 102 -#define OP_Sequence 103 /* synopsis: r[P2]=cursor[P1].ctr++ */ -#define OP_NextId 104 /* synopsis: r[P3]=get_max(space_index[P1]{Column[P2]}) */ -#define OP_NextIdEphemeral 105 /* synopsis: r[P3]=get_max(space_index[P1]{Column[P2]}) */ -#define OP_FCopy 106 /* synopsis: reg[P2@cur_frame]= reg[P1@root_frame(OPFLAG_SAME_FRAME)] */ -#define OP_Delete 107 -#define OP_ResetCount 108 -#define OP_SorterCompare 109 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ -#define OP_SorterData 110 /* synopsis: r[P2]=data */ -#define OP_RowData 111 /* synopsis: r[P2]=data */ -#define OP_NullRow 112 -#define OP_SorterInsert 113 /* synopsis: key=r[P2] */ -#define OP_IdxReplace 114 /* synopsis: key=r[P2] */ +#define OP_SCopy 76 /* synopsis: r[P2]=r[P1] */ +#define OP_IntCopy 77 /* synopsis: r[P2]=r[P1] */ +#define OP_ResultRow 78 /* synopsis: output=r[P1@P2] */ +#define OP_CollSeq 79 +#define OP_Function0 80 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_Function 81 /* synopsis: r[P3]=func(r[P2@P5]) */ +#define OP_AddImm 82 /* synopsis: r[P1]=r[P1]+P2 */ +#define OP_RealAffinity 83 +#define OP_Cast 84 /* synopsis: affinity(r[P1]) */ +#define OP_Permutation 85 +#define OP_Compare 86 /* synopsis: r[P1@P3] <-> r[P2@P3] */ +#define OP_Column 87 /* synopsis: r[P3]=PX */ +#define OP_Affinity 88 /* synopsis: affinity(r[P1@P2]) */ +#define OP_MakeRecord 89 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 90 /* synopsis: r[P2]=count() */ +#define OP_FkCheckCommit 91 +#define OP_TTransaction 92 +#define OP_ReadCookie 93 +#define OP_SetCookie 94 +#define OP_ReopenIdx 95 /* synopsis: root=P2 */ +#define OP_OpenRead 96 /* synopsis: root=P2 */ +#define OP_OpenWrite 97 /* synopsis: root=P2 */ +#define OP_OpenTEphemeral 98 /* synopsis: nColumn = P2 */ +#define OP_SorterOpen 99 +#define OP_SequenceTest 100 /* synopsis: if (cursor[P1].ctr++) pc = P2 */ +#define OP_OpenPseudo 101 /* synopsis: P3 columns in r[P2] */ +#define OP_Close 102 +#define OP_ColumnsUsed 103 +#define OP_Sequence 104 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NextId 105 /* synopsis: r[P3]=get_max(space_index[P1]{Column[P2]}) */ +#define OP_NextIdEphemeral 106 /* synopsis: r[P3]=get_max(space_index[P1]{Column[P2]}) */ +#define OP_FCopy 107 /* synopsis: reg[P2@cur_frame]= reg[P1@root_frame(OPFLAG_SAME_FRAME)] */ +#define OP_Delete 108 +#define OP_ResetCount 109 +#define OP_SorterCompare 110 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ +#define OP_SorterData 111 /* synopsis: r[P2]=data */ +#define OP_RowData 112 /* synopsis: r[P2]=data */ +#define OP_NullRow 113 +#define OP_SorterInsert 114 /* synopsis: key=r[P2] */ #define OP_Real 115 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_IdxInsert 116 /* synopsis: key=r[P2] */ -#define OP_IdxDelete 117 /* synopsis: key=r[P2@P3] */ -#define OP_Clear 118 -#define OP_ResetSorter 119 -#define OP_ParseSchema2 120 /* synopsis: rows=r[P1@P2] */ -#define OP_ParseSchema3 121 /* synopsis: name=r[P1] sql=r[P1+1] */ -#define OP_RenameTable 122 /* synopsis: P1 = root, P4 = name */ -#define OP_LoadAnalysis 123 -#define OP_DropTable 124 -#define OP_DropIndex 125 -#define OP_DropTrigger 126 -#define OP_Param 127 -#define OP_FkCounter 128 /* synopsis: fkctr[P1]+=P2 */ -#define OP_OffsetLimit 129 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ -#define OP_AggStep0 130 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggStep 131 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggFinal 132 /* synopsis: accum=r[P1] N=P2 */ -#define OP_Expire 133 -#define OP_IncMaxid 134 -#define OP_Noop 135 -#define OP_Explain 136 +#define OP_IdxReplace 116 /* synopsis: key=r[P2] */ +#define OP_IdxInsert 117 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 118 /* synopsis: key=r[P2@P3] */ +#define OP_Clear 119 +#define OP_ResetSorter 120 +#define OP_ParseSchema2 121 /* synopsis: rows=r[P1@P2] */ +#define OP_ParseSchema3 122 /* synopsis: name=r[P1] sql=r[P1+1] */ +#define OP_RenameTable 123 /* synopsis: P1 = root, P4 = name */ +#define OP_LoadAnalysis 124 +#define OP_DropTable 125 +#define OP_DropIndex 126 +#define OP_DropTrigger 127 +#define OP_Param 128 +#define OP_FkCounter 129 /* synopsis: fkctr[P1]+=P2 */ +#define OP_OffsetLimit 130 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggStep0 131 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep 132 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggFinal 133 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 134 +#define OP_IncMaxid 135 +#define OP_Noop 136 +#define OP_Explain 137 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c @@ -157,16 +158,16 @@ /* 40 */ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x01, 0x01,\ /* 48 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\ /* 56 */ 0x03, 0x03, 0x03, 0x01, 0x02, 0x02, 0x08, 0x00,\ -/* 64 */ 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10,\ -/* 72 */ 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,\ -/* 80 */ 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,\ -/* 88 */ 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\ -/* 96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\ -/* 104 */ 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 112 */ 0x00, 0x04, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00,\ -/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\ -/* 128 */ 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 136 */ 0x00,} +/* 64 */ 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10,\ +/* 72 */ 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00,\ +/* 80 */ 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00,\ +/* 88 */ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00,\ +/* 96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 104 */ 0x10, 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ +/* 112 */ 0x00, 0x00, 0x04, 0x10, 0x00, 0x04, 0x00, 0x00,\ +/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 128 */ 0x10, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 136 */ 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 49ce51096056..a194a6e72788 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 @@ -1140,6 +1140,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 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..f13650519533 --- /dev/null +++ b/test/sql/gh-2981-check-autoinc.test.lua @@ -0,0 +1,21 @@ +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") +