diff --git a/src/box/sql.c b/src/box/sql.c
index 4415b53939b1bfe16b3b48a96888299024f0756e..38eef7dfa90a01c081c066dc06b1b4c7d34e9591 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -1038,3 +1038,33 @@ sql_debug_info(struct info_handler *h)
 	info_append_int(h, "sql_found_count", sql_found_count);
 	info_end(h);
 }
+
+/**
+ * Extract maximum integer value from:
+ * @param index space_id
+ * @param index_id
+ * @param field number fieldno
+ * @param[out] fetched value in max_id
+ *
+ * @retval 0 on success, -1 otherwise.
+ *
+ * If index is empty - return 0 in max_id and success status
+ */
+int
+tarantoolSqlGetMaxId(uint32_t space_id, uint32_t index_id, uint32_t fieldno,
+		     uint64_t *max_id)
+{
+	char key[16];
+	struct tuple *tuple;
+	char *key_end = mp_encode_array(key, 0);
+	if (box_index_max(space_id, index_id, key, key_end, &tuple) != 0)
+		return -1;
+
+	/* Index is empty  */
+	if (tuple == NULL) {
+		*max_id = 0;
+		return 0;
+	}
+
+	return tuple_field_u64(tuple, fieldno, max_id);
+}
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 8adf054c409058c873c91c50386eed988006a7e2..848c6796cd2776cb28b63b1d315083d2fba5ef0e 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -851,12 +851,12 @@ void sqlite3StartTable(
   assert( pParse->pNewTable==0 );
   pParse->pNewTable = pTable;
 
-  /* If this is the magic sqlite_sequence table used by autoincrement,
+  /* If this is the magic sql_sequence table used by autoincrement,
   ** then record a pointer to this table in the main database structure
   ** so that INSERT can find the table easily.
   */
 #ifndef SQLITE_OMIT_AUTOINCREMENT
-  if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){
+  if( !pParse->nested && strcmp(zName, "sql_sequence")==0 ){
     assert( sqlite3SchemaMutexHeld(db, 0) );
     pTable->pSchema->pSeqTab = pTable;
   }
@@ -1191,12 +1191,14 @@ void sqlite3AddPrimaryKey(
       }
     }
   }
+  pTab->iAutoIncPKey = -1;
   if( nTerm==1
    && pCol
    && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
    && sortOrder!=SQLITE_SO_DESC
   ){
     pTab->iPKey = iCol;
+    pTab->iAutoIncPKey = iCol;
     pTab->keyConf = (u8)onError;
     assert( autoInc==0 || autoInc==1 );
     pTab->tabFlags |= autoInc*TF_Autoincrement;
@@ -1954,11 +1956,6 @@ void sqlite3EndTable(
 
   /* Special processing for WITHOUT ROWID Tables */
   if( tabOpts & TF_WithoutRowid ){
-    if( (p->tabFlags & TF_Autoincrement) ){
-      sqlite3ErrorMsg(pParse,
-          "AUTOINCREMENT not allowed on WITHOUT ROWID tables");
-      return;
-    }
     if( (p->tabFlags & TF_HasPrimaryKey)==0 ){
       sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName);
     }else{
@@ -2110,7 +2107,7 @@ void sqlite3EndTable(
     sqlite3VdbeAddOp1(v, OP_Close, iCursor);
 
 #ifndef SQLITE_OMIT_AUTOINCREMENT
-    /* Check to see if we need to create an sqlite_sequence table for
+    /* Check to see if we need to create an sql_sequence table for
     ** keeping track of autoincrement keys.
     */
     if( (p->tabFlags & TF_Autoincrement)!=0 ){
@@ -2118,7 +2115,7 @@ void sqlite3EndTable(
       assert( sqlite3SchemaMutexHeld(db, 0) );
       if( pDb->pSchema->pSeqTab==0 ){
         sqlite3NestedParse(pParse,
-          "CREATE TABLE sqlite_sequence(name,seq)"
+          "CREATE TABLE sql_sequence(name PRIMARY KEY,seq)"
         );
       }
     }
@@ -2466,14 +2463,14 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int isView){
   pParse->nested--;
 
 #ifndef SQLITE_OMIT_AUTOINCREMENT
-  /* Remove any entries of the sqlite_sequence table associated with
+  /* Remove any entries of the sql_sequence table associated with
   ** the table being dropped. This is done before the table is dropped
-  ** at the btree level, in case the sqlite_sequence table needs to
+  ** at the btree level, in case the sql_sequence table needs to
   ** move as a result of the drop (can happen in auto-vacuum mode).
   */
   if( pTab->tabFlags & TF_Autoincrement ){
     sqlite3NestedParse(pParse,
-      "DELETE FROM sqlite_sequence WHERE name=%Q",
+      "DELETE FROM sql_sequence WHERE name=%Q",
       pTab->zName
     );
   }
@@ -2591,7 +2588,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
     }
   }
 #endif
-  if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 
+  if( sqlite3StrNICmp(pTab->zName, "sql_sequence", 12)==0
     && sqlite3StrNICmp(pTab->zName, "sqlite_stat", 11)!=0 ){
     sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
     goto exit_drop_table;
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index d7cab4a09483e1ed28d1d4ab22586f69a8ad44f9..345afcc27a2eb6f857d6fdcd38e67c6a5e55a7f1 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -24,11 +24,11 @@
 ** for that table that is actually opened.
 */
 void
-sqlite3OpenTable(Parse * pParse,	/* Generate code into this VDBE */
-		 int iCur,	/* The cursor number of the table */
-		 Table * pTab,	/* The table to be opened */
-		 int opcode	/* OP_OpenRead or OP_OpenWrite */
-    )
+sqlite3OpenTable(Parse * pParse,   /* Generate code into this VDBE */
+		 int iCur,         /* The cursor number of the table */
+		 Table * pTab,     /* The table to be opened */
+		 int opcode        /* OP_OpenRead or OP_OpenWrite */
+		)
 {
 	Vdbe *v;
 	assert(!IsVirtual(pTab));
@@ -228,7 +228,7 @@ readsTable(Parse * p, Table * pTab)
 **
 **   (1)  Register to hold the name of the pTab table.
 **   (2)  Register to hold the maximum ROWID of pTab.
-**   (3)  Register to hold the rowid in sqlite_sequence of pTab
+**   (3)  Register to hold the rowid in sql_sequence of pTab
 **
 ** The 2nd register is the one that is returned.  That is all the
 ** insert routine needs to know about.
@@ -256,9 +256,9 @@ autoIncBegin(Parse * pParse,	/* Parsing context */
 			pInfo->pNext = pToplevel->pAinc;
 			pToplevel->pAinc = pInfo;
 			pInfo->pTab = pTab;
-			pToplevel->nMem++;	/* Register to hold name of table */
-			pInfo->regCtr = ++pToplevel->nMem;	/* Max rowid register */
-			pToplevel->nMem++;	/* Rowid in sqlite_sequence */
+			pToplevel->nMem++;		   /* Register to hold name of table */
+			pInfo->regCtr = ++pToplevel->nMem; /* Max rowid register */
+			pToplevel->nMem++;		   /* Rowid in sql_sequence */
 		}
 		memId = pInfo->regCtr;
 	}
@@ -290,13 +290,12 @@ sqlite3AutoincrementBegin(Parse * pParse)
 			/* 0  */ {OP_Null, 0, 0, 0},
 			/* 1  */ {OP_Rewind, 0, 9, 0},
 			/* 2  */ {OP_Column, 0, 0, 0},
-			/* 3  */ {OP_Ne, 0, 7, 0},
-			/* 4  */ {OP_Rowid, 0, 0, 0},
-			/* 5  */ {OP_Column, 0, 1, 0},
-			/* 6  */ {OP_Goto, 0, 9, 0},
-			/* 7  */ {OP_Next, 0, 2, 0},
-			/* 8  */ {OP_Integer, 0, 0, 0},
-			/* 9  */ {OP_Close, 0, 0, 0}
+			/* 3  */ {OP_Ne, 0, 6, 0},
+			/* 4  */ {OP_Column, 0, 1, 0},
+			/* 5  */ {OP_Goto, 0, 8, 0},
+			/* 6  */ {OP_Next, 0, 2, 0},
+			/* 7  */ {OP_Integer, 0, 0, 0},
+			/* 8  */ {OP_Close, 0, 0, 0}
 		};
 		VdbeOp *aOp;
 		pDb = &db->mdb;
@@ -314,9 +313,8 @@ sqlite3AutoincrementBegin(Parse * pParse)
 		aOp[3].p1 = memId - 1;
 		aOp[3].p3 = memId;
 		aOp[3].p5 = SQLITE_JUMPIFNULL;
-		aOp[4].p2 = memId + 1;
-		aOp[5].p3 = memId;
-		aOp[8].p2 = memId;
+		aOp[4].p3 = memId;
+		aOp[7].p2 = memId;
 	}
 }
 
@@ -338,7 +336,7 @@ autoIncStep(Parse * pParse, int memId, int regRowid)
 
 /*
 ** This routine generates the code needed to write autoincrement
-** maximum rowid values back into the sqlite_sequence register.
+** maximum rowid values back into the sql_sequence register.
 ** Every statement that might do an INSERT into an autoincrement
 ** table (either directly or through triggers) needs to call this
 ** routine just before the "exit" code.
@@ -354,11 +352,12 @@ autoIncrementEnd(Parse * pParse)
 	for (p = pParse->pAinc; p; p = p->pNext) {
 		static const int iLn = VDBE_OFFSET_LINENO(2);
 		static const VdbeOpList autoIncEnd[] = {
-			/* 0 */ {OP_NotNull, 0, 2, 0},
-			/* 1 */ {OP_NewRowid, 0, 0, 0},
-			/* 2 */ {OP_MakeRecord, 0, 2, 0},
-			/* 3 */ {OP_Insert, 0, 0, 0},
-			/* 4 */ {OP_Close, 0, 0, 0}
+			/* 0 */ {OP_SeekGE, 0, 3, 0},
+			/* 1 */ {OP_IdxGT, 0, 3, 0},
+			/* 2 */ {OP_Delete, 0, 0, 0},
+			/* 3 */ {OP_MakeRecord, 0, 2, 0},
+			/* 4 */ {OP_IdxInsert, 0, 0, 0},
+			/* 5 */ {OP_Close, 0, 0, 0}
 		};
 		VdbeOp *aOp;
 		Db *pDb = &db->mdb;
@@ -374,13 +373,18 @@ autoIncrementEnd(Parse * pParse)
 					 iLn);
 		if (aOp == 0)
 			break;
-		aOp[0].p1 = memId + 1;
-		aOp[1].p2 = memId + 1;
-		aOp[2].p1 = memId - 1;
-		aOp[2].p3 = iRec;
-		aOp[3].p2 = iRec;
-		aOp[3].p3 = memId + 1;
-		aOp[3].p5 = OPFLAG_APPEND;
+		aOp[0].p3 = memId - 1;
+		aOp[0].p4.i = 1;
+		aOp[0].p4type = P4_INT32;
+		aOp[1].p3 = memId - 1;
+		aOp[1].p4.i = 1;
+		aOp[1].p4type = P4_INT32;
+		aOp[2].p2 = memId + 1;
+		aOp[3].p1 = memId - 1;
+		aOp[3].p3 = iRec;
+		aOp[4].p2 = iRec;
+		aOp[4].p3 = memId + 1;
+		aOp[4].p5 = OPFLAG_APPEND;
 		sqlite3ReleaseTempReg(pParse, iRec);
 	}
 }
@@ -541,6 +545,8 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 	int regIns;		/* Block of regs holding rowid+data being inserted */
 	int regRowid;		/* registers holding insert rowid */
 	int regData;		/* register holding first column to insert */
+	int regPK;		/* register containing PK for autoinc prepared
+				   for MakeRecord */
 	int *aRegIdx = 0;	/* One register allocated to each index */
 
 #ifndef SQLITE_OMIT_TRIGGER
@@ -641,7 +647,7 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 #endif				/* SQLITE_OMIT_XFER_OPT */
 
 	/* If this is an AUTOINCREMENT table, look up the sequence number in the
-	 ** sqlite_sequence table and store it in memory cell regAutoinc.
+	 ** sql_sequence table and store it in memory cell regAutoinc.
 	 */
 	regAutoinc = autoIncBegin(pParse, pTab);
 
@@ -1014,7 +1020,11 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 				VdbeCoverage(v);
 			}
 		} else if (IsVirtual(pTab) || withoutRowid) {
-			sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid);
+			if (pTab->iAutoIncPKey >= 0)
+				sqlite3VdbeAddOp3(v, OP_MaxId, iDataCur,
+						  pTab->iAutoIncPKey, regRowid);
+			else
+				sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid);
 		} else {
 			sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid,
 					  regAutoinc);
@@ -1026,16 +1036,26 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 		 ** with the first column.
 		 */
 		nHidden = 0;
+		regPK = -1;
 		for (i = 0; i < pTab->nCol; i++) {
 			int iRegStore = regRowid + 1 + i;
-			if (i == pTab->iPKey) {
-				/* The value of the INTEGER PRIMARY KEY column is always a NULL.
-				 ** Whenever this column is read, the rowid will be substituted
-				 ** in its place.  Hence, fill this column with a NULL to avoid
-				 ** taking up data space with information that will never be used.
-				 ** As there may be shallow copies of this value, make it a soft-NULL */
-				sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore);
-				continue;
+			if (i == pTab->iAutoIncPKey) {
+				/* PK was not specified in IDLIST and marked for
+				 * autoincrementation. Extract max ID from the
+				 * index and increment it. This'll be compared
+				 * w/ corresponding value extracted from
+				 * sql_sequence for given index later.
+				 */
+				if ((pTab->tabFlags & TF_Autoincrement)
+				    && (ipkColumn == -1)) {
+					sqlite3VdbeAddOp2(v,
+							  OP_FCopy,
+							  regAutoinc,
+							  iRegStore);
+					sqlite3VdbeAddOp2(v, OP_AddImm,
+							  iRegStore, 1);
+				}
+				regPK = iRegStore;
 			}
 			if (pColumn == 0) {
 				if (IsHiddenColumn(&pTab->aCol[i])) {
@@ -1052,27 +1072,84 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 			}
 			if (j < 0 || nColumn == 0
 			    || (pColumn && j >= pColumn->nId)) {
+				if (i == pTab->iAutoIncPKey) continue;
 				sqlite3ExprCodeFactorable(pParse,
 							  pTab->aCol[i].pDflt,
 							  iRegStore);
-			} else if (useTempTable) {
-				sqlite3VdbeAddOp3(v, OP_Column, srcTab, j,
-						  iRegStore);
+			} else  if (useTempTable) {
+				if ((pTab->tabFlags & TF_Autoincrement)
+				    && (i == pTab->iAutoIncPKey)) {
+					int regTmp = ++pParse->nMem ;
+					/* Emit code which doesn't override
+					 * autoinc-ed value with select result
+					 * in case if result is NULL value.
+					 */
+					sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regTmp);
+					sqlite3VdbeAddOp2(v, OP_FCopy, regTmp, iRegStore);
+					sqlite3VdbeChangeP3(v, -1, OPFLAG_SAME_FRAME | OPFLAG_NOOP_IF_NULL);
+				} else {
+					sqlite3VdbeAddOp3(v, OP_Column, srcTab, j,
+							  iRegStore);
+				}
 			} else if (pSelect) {
 				if (regFromSelect != regData) {
-					sqlite3VdbeAddOp2(v, OP_SCopy,
-							  regFromSelect + j,
-							  iRegStore);
+					if ((pTab->tabFlags & TF_Autoincrement)
+					    && (i == pTab->iAutoIncPKey)) {
+						/* Emit code which doesn't override
+						 * autoinc-ed value with select result
+						 * in case that result is NULL
+						 */
+						sqlite3VdbeAddOp2(v, OP_FCopy,
+								  regFromSelect + j,
+								  iRegStore);
+						sqlite3VdbeChangeP3(v,
+								    -1,
+								    OPFLAG_SAME_FRAME
+								    | OPFLAG_NOOP_IF_NULL);
+					} else {
+						sqlite3VdbeAddOp2(v, OP_SCopy,
+								  regFromSelect + j,
+								  iRegStore);
+					}
 				}
 			} else {
+				if (i == pTab->iAutoIncPKey) {
+					if (pList->a[j].pExpr->op == TK_NULL)
+						continue;
+
+					if (pList->a[j].pExpr->op == TK_REGISTER) {
+						/* Emit code which doesn't override
+						 * autoinc-ed value with select result
+						 * in case that result is NULL
+						 */
+						sqlite3VdbeAddOp2(v, OP_FCopy,
+								  pList->a[j].pExpr->iTable,
+								  iRegStore);
+						sqlite3VdbeChangeP3(v,
+								    -1,
+								    OPFLAG_SAME_FRAME
+								    | OPFLAG_NOOP_IF_NULL);
+						continue;
+					}
+				}
+
 				sqlite3ExprCode(pParse, pList->a[j].pExpr,
 						iRegStore);
 			}
 		}
 
-    /* Generate code to check constraints and generate index keys and
-    ** do the insertion.
-    */
+		/* If value in regAutoinc exceeds one contained in
+		   regPK, need to update it.  */
+		if (pTab->tabFlags & TF_Autoincrement) {
+			/* No way there's no PK in the table.  */
+			assert( regPK >= 0);
+
+			autoIncStep(pParse, regAutoinc, regPK);
+		}
+
+		/* Generate code to check constraints and generate index keys
+		   and do the insertion.
+		*/
 #ifndef SQLITE_OMIT_VIRTUALTABLE
 		if (IsVirtual(pTab)) {
 			const char *pVTab =
@@ -1147,7 +1224,7 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 	}
 
  insert_end:
-	/* Update the sqlite_sequence table by storing the content of the
+	/* Update the sql_sequence table by storing the content of the
 	 ** maximum rowid counter values recorded while inserting into
 	 ** autoincrement tables.
 	 */
diff --git a/src/box/sql/opcodes.c b/src/box/sql/opcodes.c
index 804c5a0fa5f0fedcfcd2c9ff4739a3499e3f8fe3..5d3b25e4b98ae31f764cecdc20f7d7cc32c28c80 100644
--- a/src/box/sql/opcodes.c
+++ b/src/box/sql/opcodes.c
@@ -126,57 +126,59 @@ const char *sqlite3OpcodeName(int i){
     /* 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(""),
+    /* 115 */ "MaxId"            OpHelp("r[P3]=get_max(space_index[P1]{Column[P2]})"),
+    /* 116 */ "FCopy"            OpHelp("reg[P2@cur_frame]= reg[P1@root_frame(OPFLAG_SAME_FRAME)]"),
+    /* 117 */ "NewRowid"         OpHelp("r[P2]=rowid"),
+    /* 118 */ "Insert"           OpHelp("intkey=r[P3] data=r[P2]"),
+    /* 119 */ "InsertInt"        OpHelp("intkey=P3 data=r[P2]"),
+    /* 120 */ "Delete"           OpHelp(""),
+    /* 121 */ "ResetCount"       OpHelp(""),
+    /* 122 */ "SorterCompare"    OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
+    /* 123 */ "SorterData"       OpHelp("r[P2]=data"),
+    /* 124 */ "RowData"          OpHelp("r[P2]=data"),
+    /* 125 */ "Rowid"            OpHelp("r[P2]=rowid"),
+    /* 126 */ "NullRow"          OpHelp(""),
+    /* 127 */ "SorterInsert"     OpHelp("key=r[P2]"),
+    /* 128 */ "IdxInsert"        OpHelp("key=r[P2]"),
+    /* 129 */ "IdxDelete"        OpHelp("key=r[P2@P3]"),
+    /* 130 */ "Seek"             OpHelp("Move P3 to P1.rowid"),
     /* 131 */ "Real"             OpHelp("r[P2]=P4"),
-    /* 132 */ "Clear"            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(""),
+    /* 132 */ "IdxRowid"         OpHelp("r[P2]=rowid"),
+    /* 133 */ "Destroy"          OpHelp(""),
+    /* 134 */ "Clear"            OpHelp(""),
+    /* 135 */ "ResetSorter"      OpHelp(""),
+    /* 136 */ "CreateIndex"      OpHelp("r[P2]=root iDb=P1"),
+    /* 137 */ "CreateTable"      OpHelp("r[P2]=root iDb=P1"),
+    /* 138 */ "ParseSchema"      OpHelp(""),
+    /* 139 */ "ParseSchema2"     OpHelp("rows=r[P1@P2] iDb=P3"),
+    /* 140 */ "ParseSchema3"     OpHelp("name=r[P1] sql=r[P1+1] iDb=P2"),
+    /* 141 */ "LoadAnalysis"     OpHelp(""),
+    /* 142 */ "DropTable"        OpHelp(""),
+    /* 143 */ "DropIndex"        OpHelp(""),
+    /* 144 */ "DropTrigger"      OpHelp(""),
+    /* 145 */ "IntegrityCk"      OpHelp(""),
+    /* 146 */ "RowSetAdd"        OpHelp("rowset(P1)=r[P2]"),
+    /* 147 */ "Param"            OpHelp(""),
+    /* 148 */ "FkCounter"        OpHelp("fkctr[P1]+=P2"),
+    /* 149 */ "MemMax"           OpHelp("r[P1]=max(r[P1],r[P2])"),
+    /* 150 */ "OffsetLimit"      OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
+    /* 151 */ "AggStep0"         OpHelp("accum=r[P3] step(r[P2@P5])"),
+    /* 152 */ "AggStep"          OpHelp("accum=r[P3] step(r[P2@P5])"),
+    /* 153 */ "AggFinal"         OpHelp("accum=r[P1] N=P2"),
+    /* 154 */ "Expire"           OpHelp(""),
+    /* 155 */ "TableLock"        OpHelp("iDb=P1 root=P2 write=P3"),
+    /* 156 */ "VBegin"           OpHelp(""),
+    /* 157 */ "VCreate"          OpHelp(""),
+    /* 158 */ "VDestroy"         OpHelp(""),
+    /* 159 */ "VOpen"            OpHelp(""),
+    /* 160 */ "VColumn"          OpHelp("r[P3]=vcolumn(P2)"),
+    /* 161 */ "VRename"          OpHelp(""),
+    /* 162 */ "Pagecount"        OpHelp(""),
+    /* 163 */ "MaxPgcnt"         OpHelp(""),
+    /* 164 */ "CursorHint"       OpHelp(""),
+    /* 165 */ "IncMaxid"         OpHelp(""),
+    /* 166 */ "Noop"             OpHelp(""),
+    /* 167 */ "Explain"          OpHelp(""),
   };
   return azName[i];
 }
diff --git a/src/box/sql/opcodes.h b/src/box/sql/opcodes.h
index 578783e1650d9bb042389ee74bbc65a6c313485e..5992f8d06385dc9d0bf7ccfa5c30f32087c07b12 100644
--- a/src/box/sql/opcodes.h
+++ b/src/box/sql/opcodes.h
@@ -115,57 +115,59 @@
 #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_MaxId         115 /* synopsis: r[P3]=get_max(space_index[P1]{Column[P2]}) */
+#define OP_FCopy         116 /* synopsis: reg[P2@cur_frame]= reg[P1@root_frame(OPFLAG_SAME_FRAME)] */
+#define OP_NewRowid      117 /* synopsis: r[P2]=rowid                      */
+#define OP_Insert        118 /* synopsis: intkey=r[P3] data=r[P2]          */
+#define OP_InsertInt     119 /* synopsis: intkey=P3 data=r[P2]             */
+#define OP_Delete        120
+#define OP_ResetCount    121
+#define OP_SorterCompare 122 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
+#define OP_SorterData    123 /* synopsis: r[P2]=data                       */
+#define OP_RowData       124 /* synopsis: r[P2]=data                       */
+#define OP_Rowid         125 /* synopsis: r[P2]=rowid                      */
+#define OP_NullRow       126
+#define OP_SorterInsert  127 /* synopsis: key=r[P2]                        */
+#define OP_IdxInsert     128 /* synopsis: key=r[P2]                        */
+#define OP_IdxDelete     129 /* synopsis: key=r[P2@P3]                     */
+#define OP_Seek          130 /* synopsis: Move P3 to P1.rowid              */
 #define OP_Real          131 /* same as TK_FLOAT, synopsis: r[P2]=P4       */
-#define OP_Clear         132
-#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
+#define OP_IdxRowid      132 /* synopsis: r[P2]=rowid                      */
+#define OP_Destroy       133
+#define OP_Clear         134
+#define OP_ResetSorter   135
+#define OP_CreateIndex   136 /* synopsis: r[P2]=root iDb=P1                */
+#define OP_CreateTable   137 /* synopsis: r[P2]=root iDb=P1                */
+#define OP_ParseSchema   138
+#define OP_ParseSchema2  139 /* synopsis: rows=r[P1@P2] iDb=P3             */
+#define OP_ParseSchema3  140 /* synopsis: name=r[P1] sql=r[P1+1] iDb=P2    */
+#define OP_LoadAnalysis  141
+#define OP_DropTable     142
+#define OP_DropIndex     143
+#define OP_DropTrigger   144
+#define OP_IntegrityCk   145
+#define OP_RowSetAdd     146 /* synopsis: rowset(P1)=r[P2]                 */
+#define OP_Param         147
+#define OP_FkCounter     148 /* synopsis: fkctr[P1]+=P2                    */
+#define OP_MemMax        149 /* synopsis: r[P1]=max(r[P1],r[P2])           */
+#define OP_OffsetLimit   150 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
+#define OP_AggStep0      151 /* synopsis: accum=r[P3] step(r[P2@P5])       */
+#define OP_AggStep       152 /* synopsis: accum=r[P3] step(r[P2@P5])       */
+#define OP_AggFinal      153 /* synopsis: accum=r[P1] N=P2                 */
+#define OP_Expire        154
+#define OP_TableLock     155 /* synopsis: iDb=P1 root=P2 write=P3          */
+#define OP_VBegin        156
+#define OP_VCreate       157
+#define OP_VDestroy      158
+#define OP_VOpen         159
+#define OP_VColumn       160 /* synopsis: r[P3]=vcolumn(P2)                */
+#define OP_VRename       161
+#define OP_Pagecount     162
+#define OP_MaxPgcnt      163
+#define OP_CursorHint    164
+#define OP_IncMaxid      165
+#define OP_Noop          166
+#define OP_Explain       167
 
 /* Properties such as "out2" or "jump" that are specified in
 ** comments following the "case" for each opcode in the vdbe.c
@@ -192,13 +194,14 @@
 /*  88 */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,\
 /*  96 */ 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00,\
 /* 104 */ 0x00, 0x00, 0x00, 0x00, 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, 0x10, 0x00, 0x00, 0x10, 0x10,\
-/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 144 */ 0x06, 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00,\
+/* 112 */ 0x00, 0x00, 0x10, 0x20, 0x10, 0x10, 0x00, 0x00,\
+/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04,\
+/* 128 */ 0x04, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00,\
+/* 136 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 144 */ 0x00, 0x00, 0x06, 0x10, 0x00, 0x04, 0x1a, 0x00,\
 /* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 160 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,}
+/* 160 */ 0x00, 0x00, 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/sqliteInt.h b/src/box/sql/sqliteInt.h
index eed00980e1a47291396da2f8f92179cc5ac5a7e4..e48d549a6c399364156252d5c50f811445c121ac 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -1785,6 +1785,8 @@ struct Table {
   int tnum;            /* Root BTree page for this table */
   u32 nTabRef;         /* Number of pointers to this Table */
   i16 iPKey;           /* If not negative, use aCol[iPKey] as the rowid */
+  i16 iAutoIncPKey;    /* If PK is marked INTEGER PRIMARY KEY AUTOINCREMENT, store
+                          column number here, -1 otherwise Tarantool specifics */
   i16 nCol;            /* Number of columns in this table */
   LogEst nRowLogEst;   /* Estimated rows in table - from sqlite_stat1 table */
   LogEst szTabRow;     /* Estimated size of each table row in bytes */
@@ -3007,6 +3009,13 @@ struct AuthContext {
 #define OPFLAG_SAVEPOSITION  0x02    /* OP_Delete: keep cursor position */
 #define OPFLAG_AUXDELETE     0x04    /* OP_Delete: index in a DELETE op */
 
+#define OPFLAG_SAME_FRAME    0x01    /* OP_FCopy: use same frame for source
+                                      * register
+                                      */
+#define OPFLAG_NOOP_IF_NULL  0x02    /* OP_FCopy: if source register is NULL
+                                      * then do nothing
+                                      */
+
 /*
  * Each trigger present in the database schema is stored as an instance of
  * struct Trigger.
diff --git a/src/box/sql/tarantoolInt.h b/src/box/sql/tarantoolInt.h
index 3f8863bdbe19b124f1fa7d70df41e09c14825a7a..ba75d5e6807eba5ad438fee04c11b420469185ed 100644
--- a/src/box/sql/tarantoolInt.h
+++ b/src/box/sql/tarantoolInt.h
@@ -6,6 +6,8 @@
 ** that's why we are using a weird naming schema.
 */
 
+#include <stdint.h>
+
 /*
  * Tarantool system spaces.
  */
@@ -96,3 +98,9 @@ int tarantoolSqlite3MakeIdxParts(Index *index, void *buf);
  * If buf==NULL estimate result size.
  */
 int tarantoolSqlite3MakeIdxOpts(Index *index, const char *zSql, void *buf);
+
+/*
+ * Fetch maximum value from ineger column number `fieldno` of space_id/index_id
+ * Return 0 on success, -1 otherwise
+ */
+int tarantoolSqlGetMaxId(uint32_t space_id, uint32_t index_id, uint32_t fieldno, uint64_t *max_id);
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index cef983eedf15791323eb415f352566916f39fcba..4db3e60cba7b3ba839a700daa368abcf84876b5a 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -4056,6 +4056,69 @@ case OP_Sequence: {           /* out2 */
   break;
 }
 
+/* Opcode: MaxId P1 P2 P3 * *
+** Synopsis: r[P3]=get_max(space_index[P1]{Column[P2]})
+**
+** Get next Id of the table. P1 is a table cursor, P2 is column
+** number. Return in P3 maximum id found in provided column.
+**
+** This opcode is Tarantool specific and will segfault in case
+** of SQLite cursor.
+*/
+case OP_MaxId: {     /* out3 */
+  VdbeCursor *pC;    /* The VDBE cursor */
+  int p2;            /* Column number, which stores the id */
+  int pgno;          /* Page number of the cursor */
+  pC = p->apCsr[pOp->p1];
+  p2 = pOp->p2;
+  pOut = &aMem[pOp->p3];
+
+  /* This opcode is Tarantool specific.  */
+  assert( pC->uc.pCursor->curFlags & BTCF_TaCursor );
+
+  pgno = pC->pgnoRoot;
+
+  tarantoolSqlGetMaxId(SQLITE_PAGENO_TO_SPACEID(pgno), SQLITE_PAGENO_TO_INDEXID(pgno), p2, &pOut->u.i);
+
+  pOut->flags = MEM_Int;
+  break;
+}
+
+/* Opcode: FCopy P1 P2 P3 * *
+** Synopsis: reg[P2@cur_frame]= reg[P1@root_frame(OPFLAG_SAME_FRAME)]
+**
+** Copy integer value of register P1 in root frame in to register P2 of current
+** frame. If current frame is topmost - copy within signle frame.
+** Source register must hold integer value.
+**
+** If P3's flag OPFLAG_SAME_FRAME is set, do shallow copy of register within
+** same frame, still making sure the value is integer.
+**
+** If P3's flag OPFLAG_NOOP_IF_NULL is set, then do nothing if reg[P1] is NULL
+*/
+case OP_FCopy: {     /* out2 */
+  VdbeFrame *pFrame;
+  Mem *pIn1, *pOut;
+  if( p->pFrame && ((pOp->p3 & OPFLAG_SAME_FRAME) == 0)) {
+    for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
+    pIn1 = &pFrame->aMem[pOp->p1];
+  }else{
+    pIn1 = &aMem[pOp->p1];
+  }
+
+  if ((pOp->p3 & OPFLAG_NOOP_IF_NULL) && (pIn1->flags & MEM_Null)) {
+    /* Flag is set and register is NULL -> do nothing  */
+  } else {
+    assert( memIsValid(pIn1) );
+    assert( pIn1->flags &  MEM_Int);
+
+    pOut = &aMem[pOp->p2];
+    MemSetTypeFlag(pOut, MEM_Int);
+
+    pOut->u.i = pIn1->u.i;
+  }
+  break;
+}
 
 /* Opcode: NewRowid P1 P2 P3 * *
 ** Synopsis: r[P2]=rowid
diff --git a/test/sql-tap/autoinc.test.lua b/test/sql-tap/autoinc.test.lua
new file mode 100755
index 0000000000000000000000000000000000000000..8c2dc2a8024821807dd515a24faff4b1ee5116a1
--- /dev/null
+++ b/test/sql-tap/autoinc.test.lua
@@ -0,0 +1,901 @@
+#!/usr/bin/env tarantool
+test = require("sqltester")
+test:plan(53)
+
+--!./tcltestrunner.lua
+-- 2004 November 12
+--
+-- The author disclaims copyright to this source code.  In place of
+-- a legal notice, here is a blessing:
+--
+--    May you do good and not evil.
+--    May you find forgiveness for yourself and forgive others.
+--    May you share freely, never taking more than you give.
+--
+---------------------------------------------------------------------------
+-- This file implements regression tests for SQLite library.  The
+-- focus of this script is testing the AUTOINCREMENT features.
+--
+-- $Id: autoinc.test,v 1.14 2009/06/23 20:28:54 drh Exp $
+--
+-- ["set","testdir",[["file","dirname",["argv0"]]]]
+-- ["source",[["testdir"],"\/tester.tcl"]]
+-- If the library is not compiled with autoincrement support then
+-- skip all tests in this file.
+--
+
+-- Add a table with the AUTOINCREMENT feature.  Verify that the
+-- SQLITE_SEQUENCE table gets created.
+--
+test:do_execsql_test(
+    "autoinc-1.2",
+    [[
+        CREATE TABLE t1(x INTEGER PRIMARY KEY AUTOINCREMENT, y);
+    ]], {
+        -- <autoinc-1.2>
+
+        -- </autoinc-1.2>
+    })
+
+-- The SQLITE_SEQUENCE table is initially empty
+--
+test:do_execsql_test(
+    "autoinc-1.3",
+    [[
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-1.3>
+
+        -- </autoinc-1.3>
+    })
+
+-- Close and reopen the database.  Verify that everything is still there.
+--
+-- test:do_test(
+--     "autoinc-1.4",
+--     function()
+--         db("close")
+--         sqlite3("db", "test.db")
+--         return test:execsql([[
+--             SELECT * FROM sql_sequence;
+--         ]])
+--     end, {
+--         -- <autoinc-1.4>
+
+--         -- </autoinc-1.4>
+--     })
+
+-- We are not allowed to drop the sqlite_sequence table.
+--
+test:do_catchsql_test(
+    "autoinc-1.5",
+    [[
+        DROP TABLE sql_sequence
+    ]], {
+        -- <autoinc-1.5>
+        1, "table sql_sequence may not be dropped"
+        -- </autoinc-1.5>
+    })
+
+test:do_execsql_test(
+    "autoinc-1.6",
+    [[
+        SELECT name FROM _space WHERE name NOT IN (SELECT name FROM _space WHERE name LIKE '\_%' ESCAPE '\')
+    ]], {
+        -- <autoinc-1.6>
+        "t1", "sql_sequence"
+        -- </autoinc-1.6>
+    })
+
+-- Insert an entries into the t1 table and make sure the largest key
+-- is always recorded in the sqlite_sequence table.
+--
+test:do_execsql_test(
+    "autoinc-2.1",
+    [[
+        --SELECT * FROM sql_sequence
+    ]], {
+        -- <autoinc-2.1>
+
+        -- </autoinc-2.1>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.2",
+    [[
+        INSERT INTO t1 VALUES(12,34);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.2>
+        "t1", 12
+        -- </autoinc-2.2>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.3",
+    [[
+        INSERT INTO t1 VALUES(1,23);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.3>
+        "t1", 12
+        -- </autoinc-2.3>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.4",
+    [[
+        INSERT INTO t1 VALUES(123,456);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.4>
+        "t1", 123
+        -- </autoinc-2.4>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.5",
+    [[
+        INSERT INTO t1 VALUES(NULL,567);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.5>
+        "t1", 124
+        -- </autoinc-2.5>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.6",
+    [[
+        DELETE FROM t1 WHERE y=567;
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.6>
+        "t1", 124
+        -- </autoinc-2.6>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.7",
+    [[
+        INSERT INTO t1 VALUES(NULL,567);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.7>
+        "t1", 125
+        -- </autoinc-2.7>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.8",
+    [[
+        DELETE FROM t1;
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.8>
+        "t1", 125
+        -- </autoinc-2.8>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.9",
+    [[
+        INSERT INTO t1 VALUES(12,34);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.9>
+        "t1", 125
+        -- </autoinc-2.9>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.10",
+    [[
+        INSERT INTO t1 VALUES(125,456);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.10>
+        "t1", 125
+        -- </autoinc-2.10>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.11",
+    [[
+        INSERT INTO t1 VALUES(-1234567,-1);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.11>
+        "t1", 125
+        -- </autoinc-2.11>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.12",
+    [[
+        INSERT INTO t1 VALUES(234,5678);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.12>
+        "t1", 234
+        -- </autoinc-2.12>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.13",
+    [[
+        DELETE FROM t1;
+        INSERT INTO t1 VALUES(NULL,1);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.13>
+        "t1", 235
+        -- </autoinc-2.13>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.14",
+    [[
+        SELECT * FROM t1;
+    ]], {
+        -- <autoinc-2.14>
+        235, 1
+        -- </autoinc-2.14>
+    })
+
+-- # Manually change the autoincrement values in sqlite_sequence.
+-- #
+test:do_execsql_test(
+    "autoinc-2.20",
+    [[
+        UPDATE sql_sequence SET seq=1234 WHERE name='t1';
+        INSERT INTO t1 VALUES(NULL,2);
+        SELECT * FROM t1;
+    ]], {
+        -- <autoinc-2.20>
+        235, 1, 1235, 2
+        -- </autoinc-2.20>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.21",
+    [[
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.21>
+        "t1", 1235
+        -- </autoinc-2.21>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.22",
+    [[
+        UPDATE sql_sequence SET seq=NULL WHERE name='t1';
+        INSERT INTO t1 VALUES(NULL,3);
+        SELECT * FROM t1;
+    ]], {
+        -- <autoinc-2.22>
+        235, 1, 1235, 2, 1236, 3
+        -- </autoinc-2.22>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.23",
+    [[
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.23>
+        "t1", 1236
+        -- </autoinc-2.23>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.24",
+    [[
+        UPDATE sql_sequence SET seq='a-string' WHERE name='t1';
+        INSERT INTO t1 VALUES(NULL,4);
+        SELECT * FROM t1;
+    ]], {
+        -- <autoinc-2.24>
+        235, 1, 1235, 2, 1236, 3, 1237, 4
+        -- </autoinc-2.24>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.25",
+    [[
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.25>
+        "t1", 1237
+        -- </autoinc-2.25>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.26",
+    [[
+        DELETE FROM sql_sequence WHERE name='t1';
+        INSERT INTO t1 VALUES(NULL,5);
+        SELECT * FROM t1;
+    ]], {
+        -- <autoinc-2.26>
+        235, 1, 1235, 2, 1236, 3, 1237, 4, 1238, 5
+        -- </autoinc-2.26>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.27",
+    [[
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.27>
+        "t1", 1238
+        -- </autoinc-2.27>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.28",
+    [[
+        UPDATE sql_sequence SET seq='-12345678901234567890'
+          WHERE name='t1';
+        INSERT INTO t1 VALUES(NULL,6);
+        SELECT * FROM t1;
+    ]], {
+        -- <autoinc-2.28>
+        235, 1, 1235, 2, 1236, 3, 1237, 4, 1238, 5, 1239, 6
+        -- </autoinc-2.28>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.29",
+    [[
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.29>
+        "t1", 1239
+        -- </autoinc-2.29>
+    })
+
+-- # Test multi-row inserts
+-- #
+test:do_execsql_test(
+    "autoinc-2.50",
+    [[
+        DELETE FROM t1 WHERE y>=3;
+        INSERT INTO t1 SELECT NULL, y+2 FROM t1;
+        SELECT * FROM t1;
+    ]], {
+        -- <autoinc-2.50>
+        235, 1, 1235, 2, 1240, 3, 1241, 4
+        -- </autoinc-2.50>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.51",
+    [[
+        SELECT * FROM sql_sequence
+    ]], {
+        -- <autoinc-2.51>
+        "t1", 1241
+        -- </autoinc-2.51>
+    })
+
+-- ifcapable tempdb {
+--   do_test autoinc-2.52 {
+--     execsql {
+--       CREATE TEMP TABLE t2 AS SELECT y FROM t1;
+--     }
+--     execsql {
+--       INSERT INTO t1 SELECT NULL, y+4 FROM t2;
+--       SELECT * FROM t1;
+--     }
+--   } {235 1 1235 2 1240 3 1241 4 1242 5 1243 6 1244 7 1245 8}
+--   do_test autoinc-2.53 {
+--     execsql {
+--       SELECT * FROM sqlite_sequence
+--     }
+--   } {t1 1245}
+--   do_test autoinc-2.54 {
+--     execsql {
+--       DELETE FROM t1;
+--       INSERT INTO t1 SELECT NULL, y FROM t2;
+--       SELECT * FROM t1;
+--     }
+--   } {1246 1 1247 2 1248 3 1249 4}
+--   do_test autoinc-2.55 {
+--     execsql {
+--       SELECT * FROM sqlite_sequence
+--     }
+--   } {t1 1249}
+-- }
+-- # Create multiple AUTOINCREMENT tables.  Make sure all sequences are
+-- # tracked separately and do not interfere with one another.
+-- #
+test:do_test(
+    "autoinc-2.70",
+    function()
+        test:catchsql([[
+            DROP TABLE t2;
+        ]])
+        return test:execsql([[
+            CREATE TABLE t2(d, e INTEGER PRIMARY KEY AUTOINCREMENT, f);
+            INSERT INTO t2(d) VALUES(1);
+            SELECT * FROM sql_sequence;
+        ]])
+    end, {
+        -- <autoinc-2.70>
+        "t1", 1241, "t2", 1
+        -- </autoinc-2.70>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.71",
+    [[
+        INSERT INTO t2(d) VALUES(2);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.71>
+        "t1", 1241, "t2", 2
+        -- </autoinc-2.71>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.72",
+    [[
+        INSERT INTO t1(x) VALUES(10000);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.72>
+        "t1", 10000, "t2", 2
+        -- </autoinc-2.72>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.73",
+    [[
+        CREATE TABLE t3(g INTEGER PRIMARY KEY AUTOINCREMENT, h);
+        INSERT INTO t3(h) VALUES(1);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.73>
+        "t1", 10000, "t2", 2, "t3", 1
+        -- </autoinc-2.73>
+    })
+
+test:do_execsql_test(
+    "autoinc-2.74",
+    [[
+        INSERT INTO t2(d,e) VALUES(3,100);
+        SELECT * FROM sql_sequence;
+    ]], {
+        -- <autoinc-2.74>
+        "t1", 10000, "t2", 100, "t3", 1
+        -- </autoinc-2.74>
+    })
+
+-- When a table with an AUTOINCREMENT is deleted, the corresponding entry
+-- in the SQLITE_SEQUENCE table should also be deleted.  But the SQLITE_SEQUENCE
+-- table itself should remain behind.
+--
+test:do_execsql_test(
+    "autoinc-3.1",
+    [[
+        SELECT name FROM sql_sequence
+    ]], {
+        -- <autoinc-3.1>
+        "t1", "t2", "t3"
+        -- </autoinc-3.1>
+    })
+
+test:do_execsql_test(
+    "autoinc-3.2",
+    [[
+        DROP TABLE t1;
+        SELECT name FROM sql_sequence;
+    ]], {
+        -- <autoinc-3.2>
+        "t2", "t3"
+        -- </autoinc-3.2>
+    })
+
+test:do_execsql_test(
+    "autoinc-3.3",
+    [[
+        DROP TABLE t3;
+        SELECT name FROM sql_sequence;
+    ]], {
+        -- <autoinc-3.3>
+        "t2"
+        -- </autoinc-3.3>
+    })
+
+test:do_execsql_test(
+    "autoinc-3.4",
+    [[
+        DROP TABLE t2;
+        SELECT name FROM sql_sequence;
+    ]], {
+        -- <autoinc-3.4>
+
+        -- </autoinc-3.4>
+    })
+
+-- AUTOINCREMENT on TEMP tables.
+--
+-- Tarantool: TEMP tables are not supported yet. To be uncommented. #2119
+-- test:do_execsql_test(
+--     "autoinc-4.1",
+--     [[
+--         SELECT 1, name FROM sqlite_master WHERE type='table';
+--         SELECT 2, name FROM sqlite_temp_master WHERE type='table';
+--     ]], {
+--         -- <autoinc-4.1>
+--         1, "sqlite_sequence"
+--         -- </autoinc-4.1>
+--     })
+
+-- test:do_execsql_test(
+--     "autoinc-4.2",
+--     [[
+--         CREATE TABLE t1(x INTEGER PRIMARY KEY AUTOINCREMENT, y);
+--         CREATE TEMP TABLE t3(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
+--         SELECT 1, name FROM sqlite_master WHERE type='table';
+--         SELECT 2, name FROM sqlite_temp_master WHERE type='table';
+--     ]], {
+--         -- <autoinc-4.2>
+--         1, "sqlite_sequence", 1, "t1", 2, "t3", 2, "sqlite_sequence"
+--         -- </autoinc-4.2>
+--     })
+
+-- test:do_execsql_test(
+--     "autoinc-4.3",
+--     [[
+--         SELECT 1, * FROM main.sqlite_sequence;
+--         SELECT 2, * FROM temp.sqlite_sequence;
+--     ]], {
+--         -- <autoinc-4.3>
+
+--         -- </autoinc-4.3>
+--     })
+
+-- test:do_execsql_test(
+--     "autoinc-4.4",
+--     [[
+--         INSERT INTO t1 VALUES(10,1);
+--         INSERT INTO t3 VALUES(20,2);
+--         INSERT INTO t1 VALUES(NULL,3);
+--         INSERT INTO t3 VALUES(NULL,4);
+--     ]], {
+--         -- <autoinc-4.4>
+
+--         -- </autoinc-4.4>
+--     })
+
+-- test:do_execsql_test(
+--     "autoinc-4.4.1",
+--     [[
+--         SELECT * FROM t1 UNION ALL SELECT * FROM t3;
+--     ]], {
+--         -- <autoinc-4.4.1>
+--         10, 1, 11, 3, 20, 2, 21, 4
+--         -- </autoinc-4.4.1>
+--     })
+
+
+
+-- -- ifcapable compound
+-- test:do_execsql_test(
+--     "autoinc-4.5",
+--     [[
+--         SELECT 1, * FROM main.sqlite_sequence;
+--         SELECT 2, * FROM temp.sqlite_sequence;
+--     ]], {
+--         -- <autoinc-4.5>
+--         1, "t1", 11, 2, "t3", 21
+--         -- </autoinc-4.5>
+--     })
+
+-- test:do_execsql_test(
+--     "autoinc-4.6",
+--     [[
+--         INSERT INTO t1 SELECT * FROM t3;
+--         SELECT 1, * FROM main.sqlite_sequence;
+--         SELECT 2, * FROM temp.sqlite_sequence;
+--     ]], {
+--         -- <autoinc-4.6>
+--         1, "t1", 21, 2, "t3", 21
+--         -- </autoinc-4.6>
+--     })
+
+-- test:do_execsql_test(
+--     "autoinc-4.7",
+--     [[
+--         INSERT INTO t3 SELECT x+100, y  FROM t1;
+--         SELECT 1, * FROM main.sqlite_sequence;
+--         SELECT 2, * FROM temp.sqlite_sequence;
+--     ]], {
+--         -- <autoinc-4.7>
+--         1, "t1", 21, 2, "t3", 121
+--         -- </autoinc-4.7>
+--     })
+
+-- test:do_execsql_test(
+--     "autoinc-4.8",
+--     [[
+--         DROP TABLE t3;
+--         SELECT 1, * FROM main.sqlite_sequence;
+--         SELECT 2, * FROM temp.sqlite_sequence;
+--     ]], {
+--         -- <autoinc-4.8>
+--         1, "t1", 21
+--         -- </autoinc-4.8>
+--     })
+
+-- test:do_execsql_test(
+--     "autoinc-4.9",
+--     [[
+--         CREATE TEMP TABLE t2(p INTEGER PRIMARY KEY AUTOINCREMENT, q);
+--         INSERT INTO t2 SELECT * FROM t1;
+--         DROP TABLE t1;
+--         SELECT 1, * FROM main.sqlite_sequence;
+--         SELECT 2, * FROM temp.sqlite_sequence;
+--     ]], {
+--         -- <autoinc-4.9>
+--         2, "t2", 21
+--         -- </autoinc-4.9>
+--     })
+
+-- test:do_execsql_test(
+--     "autoinc-4.10",
+--     [[
+--         DROP TABLE t2;
+--         SELECT 1, * FROM main.sqlite_sequence;
+--         SELECT 2, * FROM temp.sqlite_sequence;
+--     ]], {
+--         -- <autoinc-4.10>
+
+--         -- </autoinc-4.10>
+--     })
+
+
+
+-- Requirement REQ00310:  Make sure an insert fails if the sequence is
+-- already at its maximum value.
+--
+test:do_execsql_test(
+    "autoinc-6.1",
+    [[
+        CREATE TABLE t6(v INTEGER PRIMARY KEY AUTOINCREMENT, w);
+        INSERT INTO t6 VALUES(9223372036854775808,1);
+        INSERT INTO t6 VALUES(NULL,1);
+        -- SELECT seq FROM sql_sequence WHERE name='t6';
+    ]], {
+        -- <autoinc-6.1>
+        -- 9223372036854775807
+        -- </autoinc-6.1>
+    })
+
+test:do_catchsql_test(
+    "autoinc-6.2",
+    [[
+        INSERT INTO t6 VALUES(NULL,1);
+    ]], {
+        -- <autoinc-6.2>
+        1, "UNIQUE constraint failed: t6.v"
+        -- </autoinc-6.2>
+    })
+
+-- Allow the AUTOINCREMENT keyword inside the parentheses
+-- on a separate PRIMARY KEY designation.
+--
+test:do_execsql_test(
+    "autoinc-7.1",
+    [[
+        CREATE TABLE t7(x INTEGER, y REAL, PRIMARY KEY(x AUTOINCREMENT));
+        INSERT INTO t7(y) VALUES(123);
+        INSERT INTO t7(y) VALUES(234);
+        DELETE FROM t7;
+        INSERT INTO t7(y) VALUES(345);
+        SELECT * FROM t7;
+    ]], {
+        -- <autoinc-7.1>
+        3, 345.0
+        -- </autoinc-7.1>
+    })
+
+-- Test that if the AUTOINCREMENT is applied to a non integer primary key
+-- the error message is sensible.
+test:do_catchsql_test(
+    "autoinc-7.2",
+    [[
+        CREATE TABLE t8(x TEXT PRIMARY KEY AUTOINCREMENT);
+    ]], {
+        -- <autoinc-7.2>
+        1, "AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY"
+        -- </autoinc-7.2>
+    })
+
+-- Ticket #3148
+-- Make sure the sqlite_sequence table is not damaged when doing
+-- an empty insert - an INSERT INTO ... SELECT ... where the SELECT
+-- clause returns an empty set.
+--
+test:do_test(
+    "autoinc-9.1",
+    function()
+        return test:execsql([[
+            CREATE TABLE t2(x INTEGER PRIMARY KEY AUTOINCREMENT, y);
+            INSERT INTO t2 VALUES(NULL, 1);
+            CREATE TABLE t3(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
+            INSERT INTO t3 SELECT * FROM t2 WHERE y>1;
+
+            SELECT * FROM sql_sequence WHERE name='t3';
+        ]])
+    end, {
+        -- <autoinc-9.1>
+        "t3", 0
+        -- </autoinc-9.1>
+    })
+
+test:catchsql(" pragma recursive_triggers = off ")
+-- Ticket #3928.  Make sure that triggers to not make extra slots in
+-- the SQLITE_SEQUENCE table.
+--
+test:do_test(
+    "autoinc-3928.1",
+    function()
+        return test:execsql([[
+            CREATE TABLE t3928(a INTEGER PRIMARY KEY AUTOINCREMENT, b);
+            CREATE TRIGGER t3928r1 BEFORE INSERT ON t3928 BEGIN
+              INSERT INTO t3928(b) VALUES('before1');
+              INSERT INTO t3928(b) VALUES('before2');
+            END;
+            CREATE TRIGGER t3928r2 AFTER INSERT ON t3928 BEGIN
+              INSERT INTO t3928(b) VALUES('after1');
+              INSERT INTO t3928(b) VALUES('after2');
+            END;
+            INSERT INTO t3928(b) VALUES('test');
+            SELECT * FROM t3928 ORDER BY a;
+        ]])
+    end, {
+        -- <autoinc-3928.1>
+        1, "before1", 2, "after1", 3, "after2", 4, "before2", 5, "after1", 6, "after2", 7, "test", 8, "before1", 9, "before2", 10, "after1", 11, "before1", 12, "before2", 13, "after2"
+        -- </autoinc-3928.1>
+    })
+
+test:do_test(
+    "autoinc-3928.2",
+    function()
+        return test:execsql([[
+            SELECT * FROM sql_sequence WHERE name='t3928'
+        ]])
+    end, {
+        -- <autoinc-3928.2>
+        "t3928", 13
+        -- </autoinc-3928.2>
+    })
+
+test:do_test(
+    "autoinc-3928.3",
+    function()
+        return test:execsql([[
+            DROP TRIGGER t3928r1;
+            DROP TRIGGER t3928r2;
+            CREATE TRIGGER t3928r3 BEFORE UPDATE ON t3928
+              WHEN typeof(new.b)=='integer' BEGIN
+                 INSERT INTO t3928(b) VALUES('before-int-' || new.b);
+            END;
+            CREATE TRIGGER t3928r4 AFTER UPDATE ON t3928
+              WHEN typeof(new.b)=='integer' BEGIN
+                 INSERT INTO t3928(b) VALUES('after-int-' || new.b);
+            END;
+            DELETE FROM t3928 WHERE a!=1;
+            UPDATE t3928 SET b=456 WHERE a=1;
+            SELECT * FROM t3928 ORDER BY a;
+        ]])
+    end, {
+        -- <autoinc-3928.3>
+        1, 456, 14, "before-int-456", 15, "after-int-456"
+        -- </autoinc-3928.3>
+    })
+
+test:do_test(
+    "autoinc-3928.4",
+    function()
+        return test:execsql([[
+            SELECT * FROM sql_sequence WHERE name='t3928'
+        ]])
+    end, {
+        -- <autoinc-3928.4>
+        "t3928", 15
+        -- </autoinc-3928.4>
+    })
+
+test:do_test(
+    "autoinc-3928.5",
+    function()
+        return test:execsql([[
+            CREATE TABLE t3928b(x INTEGER PRIMARY KEY);
+            INSERT INTO t3928b VALUES(100);
+            INSERT INTO t3928b VALUES(200);
+            INSERT INTO t3928b VALUES(300);
+            DELETE FROM t3928;
+            CREATE TABLE t3928c(y INTEGER PRIMARY KEY AUTOINCREMENT, z);
+            CREATE TRIGGER t3928br1 BEFORE DELETE ON t3928b BEGIN
+              INSERT INTO t3928(b) VALUES('before-del-'||old.x);
+              INSERT INTO t3928c(z) VALUES('before-del-'||old.x);
+            END;
+            CREATE TRIGGER t3928br2 AFTER DELETE ON t3928b BEGIN
+              INSERT INTO t3928(b) VALUES('after-del-'||old.x);
+              INSERT INTO t3928c(z) VALUES('after-del-'||old.x);
+            END;
+            DELETE FROM t3928b;
+            SELECT * FROM t3928 ORDER BY a;
+        ]])
+    end, {
+        -- <autoinc-3928.5>
+        16, "before-del-100", 17, "after-del-100", 18, "before-del-200", 19, "after-del-200", 20, "before-del-300", 21, "after-del-300"
+        -- </autoinc-3928.5>
+    })
+
+test:do_test(
+    "autoinc-3928.6",
+    function()
+        return test:execsql([[
+            SELECT * FROM t3928c ORDER BY y;
+        ]])
+    end, {
+        -- <autoinc-3928.6>
+        1, "before-del-100", 2, "after-del-100", 3, "before-del-200", 4, "after-del-200", 5, "before-del-300", 6, "after-del-300"
+        -- </autoinc-3928.6>
+    })
+
+test:do_test(
+    "autoinc-3928.7",
+    function()
+        return test:execsql([[
+            SELECT * FROM sql_sequence WHERE name LIKE 't3928%' ORDER BY name;
+        ]])
+    end, {
+        -- <autoinc-3928.7>
+        "t3928", 21, "t3928c", 6
+        -- </autoinc-3928.7>
+    })
+
+-- Ticket [a696379c1f0886615541a48b35bd8181a80e88f8]
+test:do_test(
+    "autoinc-a69637.1",
+    function()
+        return test:execsql([[
+            CREATE TABLE ta69637_1(x INTEGER PRIMARY KEY AUTOINCREMENT, y);
+            CREATE TABLE ta69637_2(z INTEGER PRIMARY KEY);
+            CREATE TRIGGER ra69637_1 AFTER INSERT ON ta69637_2 BEGIN
+              INSERT INTO ta69637_1(y) VALUES(new.z+1);
+            END;
+            INSERT INTO ta69637_2 VALUES(123);
+            SELECT * FROM ta69637_1;
+        ]])
+    end, {
+        -- <autoinc-a69637.1>
+        1, 124
+        -- </autoinc-a69637.1>
+    })
+
+test:do_test(
+    "autoinc-a69637.2",
+    function()
+        return test:execsql([[
+            CREATE VIEW va69637_2 AS SELECT * FROM ta69637_2;
+            CREATE TRIGGER ra69637_2 INSTEAD OF INSERT ON va69637_2 BEGIN
+              INSERT INTO ta69637_1(y) VALUES(new.z+10000);
+            END;
+            INSERT INTO va69637_2 VALUES(123);
+            SELECT * FROM ta69637_1;
+        ]])
+    end, {
+        -- <autoinc-a69637.2>
+        1, 124, 2, 10123
+        -- </autoinc-a69637.2>
+    })
+
+test:finish_test()