/ Check-in [34fec312]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Preliminary fix for ticket #2291. This fixes the immediate problem. But we really need to write more tests for the xfer optimization in order to look for other related problems before closing this ticket. (CVS 3835)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:34fec312fd1aeabb04e07d6aa061991775c7b8a1
User & Date: drh 2007-04-10 18:17:55
Context
2007-04-11
17:54
Blind check-in of changes to fix #2294 - I have no ability to test. Gentle wince users: please test this change and if it works leave a remark on the #2294 ticket. Tnx. (CVS 3836) check-in: ca56c3e2 user: drh tags: trunk
2007-04-10
18:17
Preliminary fix for ticket #2291. This fixes the immediate problem. But we really need to write more tests for the xfer optimization in order to look for other related problems before closing this ticket. (CVS 3835) check-in: 34fec312 user: drh tags: trunk
13:51
Be careful not to use the result of sqlite3_value_blob() after changing the representation of an object. Ticket #2290. (CVS 3834) check-in: e14374e4 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/insert.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
....
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380

1381
1382
1383
1384
1385
1386
1387
....
1470
1471
1472
1473
1474
1475
1476



1477
1478
1479
1480
1481
1482
1483
....
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511





1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
....
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.183 2007/04/01 23:49:52 drh Exp $
*/
#include "sqliteInt.h"

/*
** Set P3 of the most recently inserted opcode to a column affinity
** string for index pIdx. A column affinity string has one character
** for each column in the table, according to the affinity of the column:
................................................................................
  struct SrcList_item *pItem;      /* An element of pSelect->pSrc */
  int i;                           /* Loop counter */
  int iDbSrc;                      /* The database of pSrc */
  int iSrc, iDest;                 /* Cursors from source and destination */
  int addr1, addr2;                /* Loop addresses */
  int emptyDestTest;               /* Address of test for empty pDest */
  int emptySrcTest;                /* Address of test for empty pSrc */
  int memRowid = 0;                /* A memcell containing a rowid from pSrc */
  Vdbe *v;                         /* The VDBE we are building */
  KeyInfo *pKey;                   /* Key information for an index */
  int counterMem;                  /* Memory register used by AUTOINC */


  if( pSelect==0 ){
    return 0;   /* Must be of the form  INSERT INTO ... SELECT ... */
  }
  if( pDest->pTrigger ){
    return 0;   /* tab1 must not have triggers */
  }
................................................................................
      return 0;    /* Collating sequence must be the same on all columns */
    }
    if( pDest->aCol[i].notNull && !pSrc->aCol[i].notNull ){
      return 0;    /* tab2 must be NOT NULL if tab1 is */
    }
  }
  for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){



    for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
      if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
    }
    if( pSrcIdx==0 ){
      return 0;    /* pDestIdx has no corresponding index in pSrc */
    }
  }
................................................................................
#endif
  iDbSrc = sqlite3SchemaToIndex(pParse->db, pSrc->pSchema);
  v = sqlite3GetVdbe(pParse);
  iSrc = pParse->nTab++;
  iDest = pParse->nTab++;
  counterMem = autoIncBegin(pParse, iDbDest, pDest);
  sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
  if( pDest->iPKey<0 && pDest->pIndex!=0 ){
    /* If tables do not have an INTEGER PRIMARY KEY and there
    ** are indices to be copied and the destination is not empty,
    ** we have to disallow the transfer optimization because the
    ** the rowids might change which will mess up indexing.





    */
    addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iDest, 0);
    emptyDestTest = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
    sqlite3VdbeJumpHere(v, addr1);
  }else{
    emptyDestTest = 0;
  }
  sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
  emptySrcTest = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0);
  if( pDest->pIndex!=0 ){
    sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0);
    memRowid = pParse->nMem++;
    sqlite3VdbeAddOp(v, OP_MemStore, memRowid, pDest->iPKey>=0);
  }
  if( pDest->iPKey>=0 ){
    addr1 = sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0);
    sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
    addr2 = sqlite3VdbeAddOp(v, OP_NotExists, iDest, 0);
    sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, 
                      "PRIMARY KEY must be unique", P3_STATIC);
    sqlite3VdbeJumpHere(v, addr2);
................................................................................
    sqlite3VdbeAddOp(v, OP_Integer, iDbDest, 0);
    pKey = sqlite3IndexKeyinfo(pParse, pDestIdx);
    VdbeComment((v, "# %s", pDestIdx->zName));
    sqlite3VdbeOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, 
                   (char*)pKey, P3_KEYINFO_HANDOFF);
    addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0);
    sqlite3VdbeAddOp(v, OP_RowKey, iSrc, 0);
    if( pDestIdx->onError!=OE_None ){
      sqlite3VdbeAddOp(v, OP_MemLoad, memRowid, 0);
      addr2 = sqlite3VdbeAddOp(v, OP_IsUnique, iDest, 0);
      sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, 
                    "UNIQUE constraint failed", P3_STATIC);
      sqlite3VdbeJumpHere(v, addr2);
    }
    sqlite3VdbeAddOp(v, OP_IdxInsert, iDest, 1);
    sqlite3VdbeAddOp(v, OP_Next, iSrc, addr1+1);
    sqlite3VdbeJumpHere(v, addr1);
  }
  sqlite3VdbeJumpHere(v, emptySrcTest);
  sqlite3VdbeAddOp(v, OP_Close, iSrc, 0);
  sqlite3VdbeAddOp(v, OP_Close, iDest, 0);







|







 







<



>







 







>
>
>







 







|




>
>
>
>
>









<
<
<
<
<







 







<
<
<
<
<
<
<







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
....
1370
1371
1372
1373
1374
1375
1376

1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
....
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
....
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528





1529
1530
1531
1532
1533
1534
1535
....
1561
1562
1563
1564
1565
1566
1567







1568
1569
1570
1571
1572
1573
1574
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.184 2007/04/10 18:17:55 drh Exp $
*/
#include "sqliteInt.h"

/*
** Set P3 of the most recently inserted opcode to a column affinity
** string for index pIdx. A column affinity string has one character
** for each column in the table, according to the affinity of the column:
................................................................................
  struct SrcList_item *pItem;      /* An element of pSelect->pSrc */
  int i;                           /* Loop counter */
  int iDbSrc;                      /* The database of pSrc */
  int iSrc, iDest;                 /* Cursors from source and destination */
  int addr1, addr2;                /* Loop addresses */
  int emptyDestTest;               /* Address of test for empty pDest */
  int emptySrcTest;                /* Address of test for empty pSrc */

  Vdbe *v;                         /* The VDBE we are building */
  KeyInfo *pKey;                   /* Key information for an index */
  int counterMem;                  /* Memory register used by AUTOINC */
  int destHasUniqueIdx = 0;        /* True if pDest has a UNIQUE index */

  if( pSelect==0 ){
    return 0;   /* Must be of the form  INSERT INTO ... SELECT ... */
  }
  if( pDest->pTrigger ){
    return 0;   /* tab1 must not have triggers */
  }
................................................................................
      return 0;    /* Collating sequence must be the same on all columns */
    }
    if( pDest->aCol[i].notNull && !pSrc->aCol[i].notNull ){
      return 0;    /* tab2 must be NOT NULL if tab1 is */
    }
  }
  for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
    if( pDestIdx->onError!=OE_None ){
      destHasUniqueIdx = 1;
    }
    for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
      if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
    }
    if( pSrcIdx==0 ){
      return 0;    /* pDestIdx has no corresponding index in pSrc */
    }
  }
................................................................................
#endif
  iDbSrc = sqlite3SchemaToIndex(pParse->db, pSrc->pSchema);
  v = sqlite3GetVdbe(pParse);
  iSrc = pParse->nTab++;
  iDest = pParse->nTab++;
  counterMem = autoIncBegin(pParse, iDbDest, pDest);
  sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
  if( (pDest->iPKey<0 && pDest->pIndex!=0) || destHasUniqueIdx ){
    /* If tables do not have an INTEGER PRIMARY KEY and there
    ** are indices to be copied and the destination is not empty,
    ** we have to disallow the transfer optimization because the
    ** the rowids might change which will mess up indexing.
    **
    ** Or if the destination has a UNIQUE index and is not empty,
    ** we also disallow the transfer optimization because we cannot
    ** insure that all entries in the union of DEST and SRC will be
    ** unique.
    */
    addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iDest, 0);
    emptyDestTest = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
    sqlite3VdbeJumpHere(v, addr1);
  }else{
    emptyDestTest = 0;
  }
  sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
  emptySrcTest = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0);





  if( pDest->iPKey>=0 ){
    addr1 = sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0);
    sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
    addr2 = sqlite3VdbeAddOp(v, OP_NotExists, iDest, 0);
    sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, 
                      "PRIMARY KEY must be unique", P3_STATIC);
    sqlite3VdbeJumpHere(v, addr2);
................................................................................
    sqlite3VdbeAddOp(v, OP_Integer, iDbDest, 0);
    pKey = sqlite3IndexKeyinfo(pParse, pDestIdx);
    VdbeComment((v, "# %s", pDestIdx->zName));
    sqlite3VdbeOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, 
                   (char*)pKey, P3_KEYINFO_HANDOFF);
    addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0);
    sqlite3VdbeAddOp(v, OP_RowKey, iSrc, 0);







    sqlite3VdbeAddOp(v, OP_IdxInsert, iDest, 1);
    sqlite3VdbeAddOp(v, OP_Next, iSrc, addr1+1);
    sqlite3VdbeJumpHere(v, addr1);
  }
  sqlite3VdbeJumpHere(v, emptySrcTest);
  sqlite3VdbeAddOp(v, OP_Close, iSrc, 0);
  sqlite3VdbeAddOp(v, OP_Close, iDest, 0);

Changes to test/insert4.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
222
223
224
225
226
227
228
229












230
#    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 file is testing the INSERT transfer optimization.
#
# $Id: insert4.test,v 1.3 2007/02/24 15:18:50 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# The sqlite3_xferopt_count variable is incremented whenever the 
# insert transfer optimization applies.
#
................................................................................
# "int" and "integer" are equivalent so the optimization should
# run here.
#
xfer_check insert4-3.22 1 {1 9} \
    {a int, b int} \
    {x integer, b int}














finish_test







|







 








>
>
>
>
>
>
>
>
>
>
>
>

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#    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 file is testing the INSERT transfer optimization.
#
# $Id: insert4.test,v 1.4 2007/04/10 18:17:55 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# The sqlite3_xferopt_count variable is incremented whenever the 
# insert transfer optimization applies.
#
................................................................................
# "int" and "integer" are equivalent so the optimization should
# run here.
#
xfer_check insert4-3.22 1 {1 9} \
    {a int, b int} \
    {x integer, b int}


# Ticket #2291.
#
do_test insert4-4.1 {
  execsql {
    CREATE TABLE t4(a, b, PRIMARY KEY(a,b));
    INSERT INTO t4 VALUES(NULL,0);
    INSERT INTO t4 VALUES(NULL,1);
    INSERT INTO t4 VALUES(NULL,1);
    VACUUM;   
  }
} {}

finish_test