mirror of https://github.com/sqlite/sqlite
Enhance the code generator for INSERT INTO ... SELECT so that the SELECT
generates output directly in the registers that INSERT INTO will be using, in many cases, and OP_SCopy operations can thus be avoided. FossilOrigin-Name: aa2d8b0e8154dd2f5e2c837dc11ab362b083495b
This commit is contained in:
parent
cfc6ca4179
commit
05a86c5c0f
27
manifest
27
manifest
|
@ -1,5 +1,5 @@
|
|||
C Seek\spast\sNULLs\sin\sa\stop-constrained\ssearch.\s\sAvoid\schecking\sfor\sNULLs\sin\nthe\sbody\sof\sthe\ssearch.
|
||||
D 2014-02-14T23:49:13.552
|
||||
C Enhance\sthe\scode\sgenerator\sfor\sINSERT\sINTO\s...\sSELECT\sso\sthat\sthe\sSELECT\ngenerates\soutput\sdirectly\sin\sthe\sregisters\sthat\sINSERT\sINTO\swill\sbe\susing,\nin\smany\scases,\sand\sOP_SCopy\soperations\scan\sthus\sbe\savoided.
|
||||
D 2014-02-16T01:55:49.753
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
|
@ -172,7 +172,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
|||
F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd
|
||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||
F src/delete.c 6765a421f08adbedc5d52d21760ec6dbe5123fd3
|
||||
F src/expr.c 9bea427f95665c1aa8fdc87b7678546eef50c296
|
||||
F src/expr.c 90bba0ca6ec97d6857458f08a8ad2820130e13cf
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 2ab0f5384b70594468ef3ac5c7ed8ca24bfd17d5
|
||||
F src/func.c f4499b39d66b71825514334ce67b32ff14bd19f5
|
||||
|
@ -180,7 +180,7 @@ F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486
|
|||
F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c 89526b031cf8f0e2306f02099a73cee56110c580
|
||||
F src/insert.c 36e61dd2201c34a11886487e7afb86f3451ffc52
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
|
@ -216,12 +216,12 @@ F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
|
|||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c ca8b99d894164435f5c55cb304c1b8121705c51e
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c 50961f0d0ab8f2d45ff29ec5f91d8db221330ca7
|
||||
F src/select.c ebec4d3fad7fd5aa33cd69e2f50e9c109285dc73
|
||||
F src/shell.c 3dd86bf73ccd079f0e32ef5069600586085e8239
|
||||
F src/sqlite.h.in eed7f7d66a60daaa7b4a597dcd9bad87aad9611b
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h 5b1f4e30c8332270e4c14254ef1fbcbd92a4a4c7
|
||||
F src/sqliteInt.h 82aa6a9b068b5a827e85af0b7fa12661f5874459
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
|
@ -277,7 +277,7 @@ F src/update.c a7df6fffce6bfedc578fda6136dd33e34a63f8ee
|
|||
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
||||
F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf
|
||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||
F src/vdbe.c 543ed4ed0c41b34affad239374d4c07e6e5b2401
|
||||
F src/vdbe.c 7b74ce685d05c1123b0360ce6bc377df114b8533
|
||||
F src/vdbe.h e6c4c610fcabad4fa80ebb1efc6822a9367e2b26
|
||||
F src/vdbeInt.h 5286af9067cabdb8ba57b87c0c988a931be6c6c8
|
||||
F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820
|
||||
|
@ -613,10 +613,10 @@ F test/index7.test a3baf9a625bda7fd49471e99aeae04095fbfeecf
|
|||
F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec
|
||||
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
F test/insert.test 489aa12a027c83d291f5034a83c8c32e6be1dca2
|
||||
F test/insert.test c120294273b18cf9c8b1a3158131f7a825bdba41
|
||||
F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
|
||||
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
|
||||
F test/insert4.test b00ddf82d6d4f0a6f3999f42bb6a3c813ea70707
|
||||
F test/insert4.test 4791662c50518bdd37d394cae9a7a8014e845bb3
|
||||
F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6
|
||||
F test/instr.test 737bbf80685232033f3abedc6ae92f75860b5dd2
|
||||
F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
|
||||
|
@ -1150,7 +1150,10 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
|
|||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P 3c1ae447dec8fc2af1c5105134061717594ac0e0
|
||||
R 20e62eafcdc3ac9a7a16fa36432e6177
|
||||
P e07a32f30862acf3b322d4d8deb015846d6f8f5f
|
||||
R 4c464651f87f73c0925f058052453922
|
||||
T *branch * insert-optimization
|
||||
T *sym-insert-optimization *
|
||||
T -sym-trunk *
|
||||
U drh
|
||||
Z f35a13e794e2689c6821aa3d892fcd6f
|
||||
Z fb4eb5dbe58efaaeaac33be3bebd9bdd
|
||||
|
|
|
@ -1 +1 @@
|
|||
e07a32f30862acf3b322d4d8deb015846d6f8f5f
|
||||
aa2d8b0e8154dd2f5e2c837dc11ab362b083495b
|
38
src/expr.c
38
src/expr.c
|
@ -3112,7 +3112,7 @@ int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
|
|||
** results in register target. The results are guaranteed to appear
|
||||
** in register target.
|
||||
*/
|
||||
int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||
void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||
int inReg;
|
||||
|
||||
assert( target>0 && target<=pParse->nMem );
|
||||
|
@ -3125,7 +3125,20 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will evaluate expression pExpr and store the
|
||||
** results in register target. The results are guaranteed to appear
|
||||
** in register target. If the expression is constant, then this routine
|
||||
** might choose to code the expression at initialization time.
|
||||
*/
|
||||
void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
|
||||
if( pParse->okConstFactor && sqlite3ExprIsConstant(pExpr) ){
|
||||
sqlite3ExprCodeAtInit(pParse, pExpr, target, 0);
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pExpr, target);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3140,25 +3153,16 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|||
** times. They are evaluated once and the results of the expression
|
||||
** are reused.
|
||||
*/
|
||||
int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
|
||||
void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int inReg;
|
||||
inReg = sqlite3ExprCode(pParse, pExpr, target);
|
||||
assert( target>0 );
|
||||
/* The only place, other than this routine, where expressions can be
|
||||
** converted to TK_REGISTER is internal subexpressions in BETWEEN and
|
||||
** CASE operators. Neither ever calls this routine. And this routine
|
||||
** is never called twice on the same expression. Hence it is impossible
|
||||
** for the input to this routine to already be a register. Nevertheless,
|
||||
** it seems prudent to keep the ALWAYS() in case the conditions above
|
||||
** change with future modifications or enhancements. */
|
||||
if( ALWAYS(pExpr->op!=TK_REGISTER) ){
|
||||
int iMem;
|
||||
|
||||
assert( target>0 );
|
||||
assert( pExpr->op!=TK_REGISTER );
|
||||
sqlite3ExprCode(pParse, pExpr, target);
|
||||
iMem = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, inReg, iMem);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, target, iMem);
|
||||
exprToRegister(pExpr, iMem);
|
||||
}
|
||||
return inReg;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_ENABLE_TREE_EXPLAIN)
|
||||
|
|
230
src/insert.c
230
src/insert.c
|
@ -148,7 +148,7 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
|
|||
** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can
|
||||
** run without using temporary table for the results of the SELECT.
|
||||
*/
|
||||
static int readsTable(Parse *p, int iStartAddr, int iDb, Table *pTab){
|
||||
static int readsTable(Parse *p, int iDb, Table *pTab){
|
||||
Vdbe *v = sqlite3GetVdbe(p);
|
||||
int i;
|
||||
int iEnd = sqlite3VdbeCurrentAddr(v);
|
||||
|
@ -156,7 +156,7 @@ static int readsTable(Parse *p, int iStartAddr, int iDb, Table *pTab){
|
|||
VTable *pVTab = IsVirtual(pTab) ? sqlite3GetVTable(p->db, pTab) : 0;
|
||||
#endif
|
||||
|
||||
for(i=iStartAddr; i<iEnd; i++){
|
||||
for(i=1; i<iEnd; i++){
|
||||
VdbeOp *pOp = sqlite3VdbeGetOp(v, i);
|
||||
assert( pOp!=0 );
|
||||
if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){
|
||||
|
@ -335,79 +335,6 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
|||
#endif /* SQLITE_OMIT_AUTOINCREMENT */
|
||||
|
||||
|
||||
/*
|
||||
** Generate code for a co-routine that will evaluate a subquery one
|
||||
** row at a time.
|
||||
**
|
||||
** The pSelect parameter is the subquery that the co-routine will evaluation.
|
||||
** Information about the location of co-routine and the registers it will use
|
||||
** is returned by filling in the pDest object.
|
||||
**
|
||||
** Registers are allocated as follows:
|
||||
**
|
||||
** pDest->iSDParm The register holding the next entry-point of the
|
||||
** co-routine. Run the co-routine to its next breakpoint
|
||||
** by calling "OP_Yield $X" where $X is pDest->iSDParm.
|
||||
**
|
||||
** pDest->iSdst First result register.
|
||||
**
|
||||
** pDest->nSdst Number of result registers.
|
||||
**
|
||||
** At EOF the first result register will be marked as "undefined" so that
|
||||
** the caller can know when to stop reading results.
|
||||
**
|
||||
** This routine handles all of the register allocation and fills in the
|
||||
** pDest structure appropriately.
|
||||
**
|
||||
** Here is a schematic of the generated code assuming that X is the
|
||||
** co-routine entry-point register reg[pDest->iSDParm], that EOF is the
|
||||
** completed flag reg[pDest->iSDParm+1], and R and S are the range of
|
||||
** registers that hold the result set, reg[pDest->iSdst] through
|
||||
** reg[pDest->iSdst+pDest->nSdst-1]:
|
||||
**
|
||||
** X <- A
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
** loop rows in the SELECT
|
||||
** load results into registers R..S
|
||||
** yield X
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** end co-routine R
|
||||
** B:
|
||||
**
|
||||
** To use this subroutine, the caller generates code as follows:
|
||||
**
|
||||
** [ Co-routine generated by this subroutine, shown above ]
|
||||
** S: yield X, at EOF goto E
|
||||
** if skip this row, goto C
|
||||
** if terminate loop, goto E
|
||||
** deal with this row
|
||||
** C: goto S
|
||||
** E:
|
||||
*/
|
||||
int sqlite3CodeCoroutine(Parse *pParse, Select *pSelect, SelectDest *pDest){
|
||||
int regYield; /* Register holding co-routine entry-point */
|
||||
int addrTop; /* Top of the co-routine */
|
||||
int rc; /* Result code */
|
||||
Vdbe *v; /* VDBE under construction */
|
||||
|
||||
regYield = ++pParse->nMem;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
|
||||
sqlite3SelectDestInit(pDest, SRT_Coroutine, regYield);
|
||||
rc = sqlite3Select(pParse, pSelect, pDest);
|
||||
assert( pParse->nErr==0 || rc );
|
||||
if( pParse->db->mallocFailed && rc==SQLITE_OK ) rc = SQLITE_NOMEM;
|
||||
if( rc ) return rc;
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
|
||||
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Forward declaration */
|
||||
static int xferOptimization(
|
||||
Parse *pParse, /* Parser context */
|
||||
|
@ -531,16 +458,16 @@ void sqlite3Insert(
|
|||
int iIdxCur = 0; /* First index cursor */
|
||||
int ipkColumn = -1; /* Column that is the INTEGER PRIMARY KEY */
|
||||
int endOfLoop; /* Label for the end of the insertion loop */
|
||||
int useTempTable = 0; /* Store SELECT results in intermediate table */
|
||||
int srcTab = 0; /* Data comes from this temporary cursor if >=0 */
|
||||
int addrInsTop = 0; /* Jump to label "D" */
|
||||
int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */
|
||||
int addrSelect = 0; /* Address of coroutine that implements the SELECT */
|
||||
SelectDest dest; /* Destination for SELECT on rhs of INSERT */
|
||||
int iDb; /* Index of database holding TABLE */
|
||||
Db *pDb; /* The database containing table being inserted into */
|
||||
int appendFlag = 0; /* True if the insert is likely to be an append */
|
||||
int withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */
|
||||
u8 useTempTable = 0; /* Store SELECT results in intermediate table */
|
||||
u8 appendFlag = 0; /* True if the insert is likely to be an append */
|
||||
u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */
|
||||
u8 bIdListInOrder = 1; /* True if IDLIST is in table order */
|
||||
ExprList *pList = 0; /* List of VALUES() to be inserted */
|
||||
|
||||
/* Register allocations */
|
||||
|
@ -652,6 +579,56 @@ void sqlite3Insert(
|
|||
*/
|
||||
regAutoinc = autoIncBegin(pParse, iDb, pTab);
|
||||
|
||||
/* Allocate registers for holding the rowid of the new row,
|
||||
** the content of the new row, and the assemblied row record.
|
||||
*/
|
||||
regRowid = regIns = pParse->nMem+1;
|
||||
pParse->nMem += pTab->nCol + 1;
|
||||
if( IsVirtual(pTab) ){
|
||||
regRowid++;
|
||||
pParse->nMem++;
|
||||
}
|
||||
regData = regRowid+1;
|
||||
|
||||
/* If the INSERT statement included an IDLIST term, then make sure
|
||||
** all elements of the IDLIST really are columns of the table and
|
||||
** remember the column indices.
|
||||
**
|
||||
** If the table has an INTEGER PRIMARY KEY column and that column
|
||||
** is named in the IDLIST, then record in the ipkColumn variable
|
||||
** the index into IDLIST of the primary key column. ipkColumn is
|
||||
** the index of the primary key as it appears in IDLIST, not as
|
||||
** is appears in the original table. (The index of the INTEGER
|
||||
** PRIMARY KEY in the original table is pTab->iPKey.)
|
||||
*/
|
||||
if( pColumn ){
|
||||
for(i=0; i<pColumn->nId; i++){
|
||||
pColumn->a[i].idx = -1;
|
||||
}
|
||||
for(i=0; i<pColumn->nId; i++){
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){
|
||||
pColumn->a[i].idx = j;
|
||||
if( i!=j ) bIdListInOrder = 0;
|
||||
if( j==pTab->iPKey ){
|
||||
ipkColumn = i; assert( !withoutRowid );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j>=pTab->nCol ){
|
||||
if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){
|
||||
ipkColumn = i;
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "table %S has no column named %s",
|
||||
pTabList, 0, pColumn->a[i].zName);
|
||||
pParse->checkSchema = 1;
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Figure out how many columns of data are supplied. If the data
|
||||
** is coming from a SELECT statement, then generate a co-routine that
|
||||
** produces a single row of the SELECT on each invocation. The
|
||||
|
@ -659,13 +636,24 @@ void sqlite3Insert(
|
|||
*/
|
||||
if( pSelect ){
|
||||
/* Data is coming from a SELECT. Generate a co-routine to run the SELECT */
|
||||
int rc = sqlite3CodeCoroutine(pParse, pSelect, &dest);
|
||||
if( rc ) goto insert_cleanup;
|
||||
int regYield; /* Register holding co-routine entry-point */
|
||||
int addrTop; /* Top of the co-routine */
|
||||
int rc; /* Result code */
|
||||
|
||||
regYield = ++pParse->nMem;
|
||||
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
|
||||
dest.iSdst = bIdListInOrder ? regData : 0;
|
||||
dest.nSdst = pTab->nCol;
|
||||
rc = sqlite3Select(pParse, pSelect, &dest);
|
||||
regFromSelect = dest.iSdst;
|
||||
assert( pParse->nErr==0 || rc );
|
||||
if( rc || db->mallocFailed ) goto insert_cleanup;
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
|
||||
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
|
||||
assert( pSelect->pEList );
|
||||
nColumn = pSelect->pEList->nExpr;
|
||||
assert( dest.nSdst==nColumn );
|
||||
|
||||
/* Set useTempTable to TRUE if the result of the SELECT statement
|
||||
** should be written into a temporary table (template 4). Set to
|
||||
|
@ -676,7 +664,7 @@ void sqlite3Insert(
|
|||
** of the tables being read by the SELECT statement. Also use a
|
||||
** temp table in the case of row triggers.
|
||||
*/
|
||||
if( pTrigger || readsTable(pParse, addrSelect, iDb, pTab) ){
|
||||
if( pTrigger || readsTable(pParse, iDb, pTab) ){
|
||||
useTempTable = 1;
|
||||
}
|
||||
|
||||
|
@ -725,6 +713,14 @@ void sqlite3Insert(
|
|||
}
|
||||
}
|
||||
|
||||
/* If there is no IDLIST term but the table has an integer primary
|
||||
** key, the set the ipkColumn variable to the integer primary key
|
||||
** column index in the original table definition.
|
||||
*/
|
||||
if( pColumn==0 && nColumn>0 ){
|
||||
ipkColumn = pTab->iPKey;
|
||||
}
|
||||
|
||||
/* Make sure the number of columns in the source data matches the number
|
||||
** of columns to be inserted into the table.
|
||||
*/
|
||||
|
@ -744,52 +740,6 @@ void sqlite3Insert(
|
|||
goto insert_cleanup;
|
||||
}
|
||||
|
||||
/* If the INSERT statement included an IDLIST term, then make sure
|
||||
** all elements of the IDLIST really are columns of the table and
|
||||
** remember the column indices.
|
||||
**
|
||||
** If the table has an INTEGER PRIMARY KEY column and that column
|
||||
** is named in the IDLIST, then record in the ipkColumn variable
|
||||
** the index into IDLIST of the primary key column. ipkColumn is
|
||||
** the index of the primary key as it appears in IDLIST, not as
|
||||
** is appears in the original table. (The index of the INTEGER
|
||||
** PRIMARY KEY in the original table is pTab->iPKey.)
|
||||
*/
|
||||
if( pColumn ){
|
||||
for(i=0; i<pColumn->nId; i++){
|
||||
pColumn->a[i].idx = -1;
|
||||
}
|
||||
for(i=0; i<pColumn->nId; i++){
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){
|
||||
pColumn->a[i].idx = j;
|
||||
if( j==pTab->iPKey ){
|
||||
ipkColumn = i; assert( !withoutRowid );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j>=pTab->nCol ){
|
||||
if( sqlite3IsRowid(pColumn->a[i].zName) && !withoutRowid ){
|
||||
ipkColumn = i;
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse, "table %S has no column named %s",
|
||||
pTabList, 0, pColumn->a[i].zName);
|
||||
pParse->checkSchema = 1;
|
||||
goto insert_cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is no IDLIST term but the table has an integer primary
|
||||
** key, the set the ipkColumn variable to the integer primary key
|
||||
** column index in the original table definition.
|
||||
*/
|
||||
if( pColumn==0 && nColumn>0 ){
|
||||
ipkColumn = pTab->iPKey;
|
||||
}
|
||||
|
||||
/* Initialize the count of rows to be inserted
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
|
@ -836,17 +786,6 @@ void sqlite3Insert(
|
|||
addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
||||
}
|
||||
|
||||
/* Allocate registers for holding the rowid of the new row,
|
||||
** the content of the new row, and the assemblied row record.
|
||||
*/
|
||||
regRowid = regIns = pParse->nMem+1;
|
||||
pParse->nMem += pTab->nCol + 1;
|
||||
if( IsVirtual(pTab) ){
|
||||
regRowid++;
|
||||
pParse->nMem++;
|
||||
}
|
||||
regData = regRowid+1;
|
||||
|
||||
/* Run the BEFORE and INSTEAD OF triggers, if there are any
|
||||
*/
|
||||
endOfLoop = sqlite3VdbeMakeLabel(v);
|
||||
|
@ -930,7 +869,7 @@ void sqlite3Insert(
|
|||
if( useTempTable ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regRowid);
|
||||
}else if( pSelect ){
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+ipkColumn, regRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid);
|
||||
}else{
|
||||
VdbeOp *pOp;
|
||||
sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid);
|
||||
|
@ -976,8 +915,9 @@ void sqlite3Insert(
|
|||
/* 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. */
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, iRegStore);
|
||||
** 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( pColumn==0 ){
|
||||
|
@ -994,11 +934,13 @@ void sqlite3Insert(
|
|||
}
|
||||
}
|
||||
if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore);
|
||||
sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
|
||||
}else if( useTempTable ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore);
|
||||
}else if( pSelect ){
|
||||
if( regFromSelect!=regData ){
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore);
|
||||
}
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore);
|
||||
}
|
||||
|
|
12
src/select.c
12
src/select.c
|
@ -585,13 +585,19 @@ static void selectInnerLoop(
|
|||
/* Pull the requested columns.
|
||||
*/
|
||||
nResultCol = pEList->nExpr;
|
||||
|
||||
if( pDest->iSdst==0 ){
|
||||
pDest->iSdst = pParse->nMem+1;
|
||||
pDest->nSdst = nResultCol;
|
||||
pParse->nMem += nResultCol;
|
||||
}else{
|
||||
assert( pDest->nSdst==nResultCol );
|
||||
}else if( pDest->iSdst+nResultCol > pParse->nMem ){
|
||||
/* This is an error condition that can result, for example, when a SELECT
|
||||
** on the right-hand side of an INSERT contains more result columns than
|
||||
** there are columns in the table on the left. The error will be caught
|
||||
** and reported later. But we need to make sure enough memory is allocated
|
||||
** to avoid other spurious errors in the meantime. */
|
||||
pParse->nMem += nResultCol;
|
||||
}
|
||||
pDest->nSdst = nResultCol;
|
||||
regResult = pDest->iSdst;
|
||||
if( srcTab>=0 ){
|
||||
for(i=0; i<nResultCol; i++){
|
||||
|
|
|
@ -2990,7 +2990,6 @@ void sqlite3DeleteTable(sqlite3*, Table*);
|
|||
# define sqlite3AutoincrementBegin(X)
|
||||
# define sqlite3AutoincrementEnd(X)
|
||||
#endif
|
||||
int sqlite3CodeCoroutine(Parse*, Select*, SelectDest*);
|
||||
void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int);
|
||||
void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
|
||||
IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
|
||||
|
@ -3038,11 +3037,12 @@ void sqlite3ExprCachePop(Parse*, int);
|
|||
void sqlite3ExprCacheRemove(Parse*, int, int);
|
||||
void sqlite3ExprCacheClear(Parse*);
|
||||
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
|
||||
int sqlite3ExprCode(Parse*, Expr*, int);
|
||||
void sqlite3ExprCode(Parse*, Expr*, int);
|
||||
void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
|
||||
void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8);
|
||||
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
|
||||
int sqlite3ExprCodeTarget(Parse*, Expr*, int);
|
||||
int sqlite3ExprCodeAndCache(Parse*, Expr*, int);
|
||||
void sqlite3ExprCodeAndCache(Parse*, Expr*, int);
|
||||
int sqlite3ExprCodeExprList(Parse*, ExprList*, int, u8);
|
||||
#define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */
|
||||
#define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */
|
||||
|
|
39
src/vdbe.c
39
src/vdbe.c
|
@ -994,6 +994,20 @@ case OP_Null: { /* out2-prerelease */
|
|||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SoftNull P1 * * * *
|
||||
** Synopsis: r[P1]=NULL
|
||||
**
|
||||
** Set register P1 to have the value NULL as seen by the OP_MakeRecord
|
||||
** instruction, but do not free any string or blob memory associated with
|
||||
** the register, so that if the value was a string or blob that was
|
||||
** previously copied using OP_SCopy, the copies will continue to be valid.
|
||||
*/
|
||||
case OP_SoftNull: {
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
|
||||
pOut = &aMem[pOp->p1];
|
||||
pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Blob P1 P2 * P4 *
|
||||
** Synopsis: r[P2]=P4 (len=P1)
|
||||
|
@ -2909,23 +2923,17 @@ case OP_AutoCommit: {
|
|||
|
||||
/* Opcode: Transaction P1 P2 P3 P4 P5
|
||||
**
|
||||
** Begin a transaction. The transaction ends when a Commit or Rollback
|
||||
** opcode is encountered. Depending on the ON CONFLICT setting, the
|
||||
** transaction might also be rolled back if an error is encountered.
|
||||
** Begin a transaction on database P1 if a transaction is not already
|
||||
** active.
|
||||
** If P2 is non-zero, then a write-transaction is started, or if a
|
||||
** read-transaction is already active, it is upgraded to a write-transaction.
|
||||
** If P2 is zero, then a read-transaction is started.
|
||||
**
|
||||
** P1 is the index of the database file on which the transaction is
|
||||
** started. Index 0 is the main database file and index 1 is the
|
||||
** file used for temporary tables. Indices of 2 or more are used for
|
||||
** attached databases.
|
||||
**
|
||||
** If P2 is non-zero, then a write-transaction is started. A RESERVED lock is
|
||||
** obtained on the database file when a write-transaction is started. No
|
||||
** other process can start another write transaction while this transaction is
|
||||
** underway. Starting a write transaction also creates a rollback journal. A
|
||||
** write transaction must be started before any changes can be made to the
|
||||
** database. If P2 is greater than or equal to 2 then an EXCLUSIVE lock is
|
||||
** also obtained on the file.
|
||||
**
|
||||
** If a write-transaction is started and the Vdbe.usesStmtJournal flag is
|
||||
** true (this flag is set if the Vdbe may modify more than one row and may
|
||||
** throw an ABORT exception), a statement transaction may also be opened.
|
||||
|
@ -2936,13 +2944,16 @@ case OP_AutoCommit: {
|
|||
** entire transaction. If no error is encountered, the statement transaction
|
||||
** will automatically commit when the VDBE halts.
|
||||
**
|
||||
** If P2 is zero, then a read-lock is obtained on the database file.
|
||||
**
|
||||
** If P5!=0 then this opcode also checks the schema cookie against P3
|
||||
** and the schema generation counter against P4.
|
||||
** The cookie changes its value whenever the database schema changes.
|
||||
** This operation is used to detect when that the cookie has changed
|
||||
** and that the current process needs to reread the schema.
|
||||
** and that the current process needs to reread the schema. If the schema
|
||||
** cookie in P3 differs from the schema cookie in the database header or
|
||||
** if the schema generation counter in P4 differs from the current
|
||||
** generation counter, then an SQLITE_SCHEMA error is raised and execution
|
||||
** halts. The sqlite3_step() wrapper function might then reprepare the
|
||||
** statement and rerun it from the beginning.
|
||||
*/
|
||||
case OP_Transaction: {
|
||||
Btree *pBt;
|
||||
|
|
|
@ -398,7 +398,7 @@ ifcapable compound {
|
|||
} {1 2 3 4 5 6 7 8 9}
|
||||
do_test insert-10.2 {
|
||||
catchsql {
|
||||
INSERT INTO t10 VALUES(11,12,13), (14,15);
|
||||
INSERT INTO t10 VALUES(11,12,13), (14,15), (16,17,28);
|
||||
}
|
||||
} {1 {all VALUES must have the same number of terms}}
|
||||
}
|
||||
|
|
|
@ -253,7 +253,7 @@ ifcapable vacuum {
|
|||
#
|
||||
do_test insert4-5.1 {
|
||||
# Table does not exist.
|
||||
catchsql { INSERT INTO t2 SELECT * FROM nosuchtable }
|
||||
catchsql { INSERT INTO t2 SELECT a, b FROM nosuchtable }
|
||||
} {1 {no such table: nosuchtable}}
|
||||
do_test insert4-5.2 {
|
||||
# Number of columns does not match.
|
||||
|
|
Loading…
Reference in New Issue