/ Check-in [48b77b04]
Login

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

Overview
Comment:Add a count parameter to the OP_Variable opcode and use it to simplify prepared statements that copy consecutive unnamed parameters into consecutive registers (a common case). (CVS 6309)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:48b77b04935d8942eb22f0c061f3bc5e99bbd7db
User & Date: drh 2009-02-20 03:55:05
References
2010-05-12
13:50
Remove the OP_Variable optimization of check-in [48b77b04935d894] since it can lead to malfunctions as described in ticket [26ff0c82d1e90]. check-in: 7838163d user: drh tags: trunk
12:12 New ticket [26ff0c82] Incorrect result when using unnamed "?" bindings. artifact: 3e0dd9c8 user: drh
Context
2009-02-20
10:58
Instead of using SetNumColumns, specify the number of columns in a table or index using the P4 argument. (CVS 6310) check-in: e43ed649 user: danielk1977 tags: trunk
03:55
Add a count parameter to the OP_Variable opcode and use it to simplify prepared statements that copy consecutive unnamed parameters into consecutive registers (a common case). (CVS 6309) check-in: 48b77b04 user: drh tags: trunk
03:02
Add the OP_HaltIfNull opcode and use it to simplify prepared statements for INSERTs and UPDATEs of tables with NOT NULL columns. (CVS 6308) check-in: feccad8d user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/expr.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
....
1998
1999
2000
2001
2002
2003
2004
















2005
2006
2007

2008
2009
2010
2011
2012
2013
2014
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.412 2009/02/19 14:39:25 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** Return the 'affinity' of the expression pExpr if any.
**
** If pExpr is a column, a reference to a column via an 'AS' alias,
................................................................................
      z = (char*)pExpr->token.z + 2;
      zBlob = sqlite3HexToBlob(sqlite3VdbeDb(v), z, n);
      sqlite3VdbeAddOp4(v, OP_Blob, n/2, target, 0, zBlob, P4_DYNAMIC);
      break;
    }
#endif
    case TK_VARIABLE: {
















      sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iTable, target);
      if( pExpr->token.n>1 ){
        sqlite3VdbeChangeP4(v, -1, (char*)pExpr->token.z, pExpr->token.n);

      }
      break;
    }
    case TK_REGISTER: {
      inReg = pExpr->iTable;
      break;
    }







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
....
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.413 2009/02/20 03:55:05 drh Exp $
*/
#include "sqliteInt.h"

/*
** Return the 'affinity' of the expression pExpr if any.
**
** If pExpr is a column, a reference to a column via an 'AS' alias,
................................................................................
      z = (char*)pExpr->token.z + 2;
      zBlob = sqlite3HexToBlob(sqlite3VdbeDb(v), z, n);
      sqlite3VdbeAddOp4(v, OP_Blob, n/2, target, 0, zBlob, P4_DYNAMIC);
      break;
    }
#endif
    case TK_VARIABLE: {
      int iPrior;
      VdbeOp *pOp;
      if( pExpr->token.n<=1
         && (iPrior = sqlite3VdbeCurrentAddr(v)-1)>=0
         && (pOp = sqlite3VdbeGetOp(v, iPrior))->opcode==OP_Variable
         && pOp->p1+pOp->p3==pExpr->iTable
         && pOp->p2+pOp->p3==target
         && pOp->p4.z==0
      ){
        /* If the previous instruction was a copy of the previous unnamed
        ** parameter into the previous register, then simply increment the
        ** repeat count on the prior instruction rather than making a new
        ** instruction.
        */
        pOp->p3++;
      }else{
        sqlite3VdbeAddOp3(v, OP_Variable, pExpr->iTable, target, 1);
        if( pExpr->token.n>1 ){
          sqlite3VdbeChangeP4(v, -1, (char*)pExpr->token.z, pExpr->token.n);
        }
      }
      break;
    }
    case TK_REGISTER: {
      inReg = pExpr->iTable;
      break;
    }

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990

991

992


993

994
995
996
997



998
999

1000
1001
1002
1003
1004
1005
1006
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.819 2009/02/20 03:02:25 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_SeekXX, OP_Next, or OP_Prev opcodes.  The test
................................................................................
  assert( pOp->p1 <= SQLITE_MAX_LENGTH );
  sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0);
  pOut->enc = encoding;
  UPDATE_MAX_BLOBSIZE(pOut);
  break;
}

/* Opcode: Variable P1 P2 * * *
**
** The value of variable P1 is written into register P2. A variable is
** an unknown in the original SQL string as handed to sqlite3_compile().
** Any occurrence of the '?' character in the original SQL is considered
** a variable.  Variables in the SQL string are number from left to
** right beginning with 1.  The values of variables are set using the
** sqlite3_bind() API.
*/
case OP_Variable: {           /* out2-prerelease */
  int j = pOp->p1 - 1;

  Mem *pVar;

  assert( j>=0 && j<p->nVar );




  pVar = &p->aVar[j];
  if( sqlite3VdbeMemTooBig(pVar) ){
    goto too_big;
  }



  sqlite3VdbeMemShallowCopy(pOut, &p->aVar[j], MEM_Static);
  UPDATE_MAX_BLOBSIZE(pOut);

  break;
}

/* Opcode: Move P1 P2 P3 * *
**
** Move the values in register P1..P1+P3-1 over into
** registers P2..P2+P3-1.  Registers P1..P1+P1-1 are







|







 







|

|
|
|
|
|
<

|

>

>
|
>
>

>
|
|
|
|
>
>
>
|
|
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
973
974
975
976
977
978
979
980
981
982
983
984
985
986

987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.820 2009/02/20 03:55:05 drh Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_SeekXX, OP_Next, or OP_Prev opcodes.  The test
................................................................................
  assert( pOp->p1 <= SQLITE_MAX_LENGTH );
  sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0);
  pOut->enc = encoding;
  UPDATE_MAX_BLOBSIZE(pOut);
  break;
}

/* Opcode: Variable P1 P2 P3 P4 *
**
** Transfer the values of bound parameters P1..P1+P3-1 into registers
** P2..P2+P3-1.
**
** If the parameter is named, then its name appears in P4 and P3==1.
** The P4 value is used by sqlite3_bind_parameter_name().

*/
case OP_Variable: {
  int j = pOp->p1 - 1;
  int k = pOp->p2;
  Mem *pVar;
  int n = pOp->p3;
  assert( j>=0 && j+n<=p->nVar );
  assert( k>=1 && k+n-1<=p->nMem );
  assert( pOp->p4.z==0 || pOp->p3==1 );

  while( n-- > 0 ){
    pVar = &p->aVar[j++];
    if( sqlite3VdbeMemTooBig(pVar) ){
      goto too_big;
    }
    pOut = &p->aMem[k++];
    sqlite3VdbeMemReleaseExternal(pOut);
    pOut->flags = MEM_Null;
    sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
    UPDATE_MAX_BLOBSIZE(pOut);
  }
  break;
}

/* Opcode: Move P1 P2 P3 * *
**
** Move the values in register P1..P1+P3-1 over into
** registers P2..P2+P3-1.  Registers P1..P1+P1-1 are

Changes to src/vdbeblob.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains code used to implement incremental BLOB I/O.
**
** $Id: vdbeblob.c,v 1.26 2008/10/02 14:49:02 danielk1977 Exp $
*/

#include "sqliteInt.h"
#include "vdbeInt.h"

#ifndef SQLITE_OMIT_INCRBLOB

................................................................................
    ** OP_Noop before exection.
    */
    {OP_SetNumColumns, 0, 0, 0},   /* 2: Num cols for cursor */
    {OP_OpenRead, 0, 0, 0},        /* 3: Open cursor 0 for reading */
    {OP_SetNumColumns, 0, 0, 0},   /* 4: Num cols for cursor */
    {OP_OpenWrite, 0, 0, 0},       /* 5: Open cursor 0 for read/write */

    {OP_Variable, 1, 1, 0},        /* 6: Push the rowid to the stack */
    {OP_NotExists, 0, 10, 1},      /* 7: Seek the cursor */
    {OP_Column, 0, 0, 1},          /* 8  */
    {OP_ResultRow, 1, 0, 0},       /* 9  */
    {OP_Close, 0, 0, 0},           /* 10  */
    {OP_Halt, 0, 0, 0},            /* 11 */
  };








|







 







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains code used to implement incremental BLOB I/O.
**
** $Id: vdbeblob.c,v 1.27 2009/02/20 03:55:05 drh Exp $
*/

#include "sqliteInt.h"
#include "vdbeInt.h"

#ifndef SQLITE_OMIT_INCRBLOB

................................................................................
    ** OP_Noop before exection.
    */
    {OP_SetNumColumns, 0, 0, 0},   /* 2: Num cols for cursor */
    {OP_OpenRead, 0, 0, 0},        /* 3: Open cursor 0 for reading */
    {OP_SetNumColumns, 0, 0, 0},   /* 4: Num cols for cursor */
    {OP_OpenWrite, 0, 0, 0},       /* 5: Open cursor 0 for read/write */

    {OP_Variable, 1, 1, 1},        /* 6: Push the rowid to the stack */
    {OP_NotExists, 0, 10, 1},      /* 7: Seek the cursor */
    {OP_Column, 0, 0, 1},          /* 8  */
    {OP_ResultRow, 1, 0, 0},       /* 9  */
    {OP_Close, 0, 0, 0},           /* 10  */
    {OP_Halt, 0, 0, 0},            /* 11 */
  };

Changes to test/bind.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
678
679
680
681
682
683
684
685








































































686
#    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 testing the sqlite_bind API.
#
# $Id: bind.test,v 1.46 2009/02/09 05:18:33 danielk1977 Exp $
#

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

proc sqlite_step {stmt N VALS COLS} {
  upvar VALS vals
................................................................................
} {@a @b}
do_test bind-14.3 {
  param_names db { SELECT @a FROM (SELECT NULL) WHERE 1 = @b }
} {@a @b}
do_test bind-14.4 {
  param_names db { SELECT @a, @b FROM (SELECT NULL) }
} {@a @b}









































































finish_test







|







 








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

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
#    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 testing the sqlite_bind API.
#
# $Id: bind.test,v 1.47 2009/02/20 03:55:05 drh Exp $
#

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

proc sqlite_step {stmt N VALS COLS} {
  upvar VALS vals
................................................................................
} {@a @b}
do_test bind-14.3 {
  param_names db { SELECT @a FROM (SELECT NULL) WHERE 1 = @b }
} {@a @b}
do_test bind-14.4 {
  param_names db { SELECT @a, @b FROM (SELECT NULL) }
} {@a @b}

#--------------------------------------------------------------------------
# Tests of the OP_Variable opcode where P3>1
#
do_test bind-15.1 {
  db eval {CREATE TABLE t4(a,b,c,d,e,f,g,h);}
  set VM [sqlite3_prepare db {
       INSERT INTO t4(a,b,c,d,f,g,h,e) VALUES(?,?,?,?,?,?,?,?)
  } -1 TAIL]
  sqlite3_bind_int $VM 1 1
  sqlite3_bind_int $VM 2 2
  sqlite3_bind_int $VM 3 3
  sqlite3_bind_int $VM 4 4
  sqlite3_bind_int $VM 5 5
  sqlite3_bind_int $VM 6 6
  sqlite3_bind_int $VM 7 7
  sqlite3_bind_int $VM 8 8
  sqlite3_step $VM
  sqlite3_finalize $VM
  db eval {SELECT * FROM t4}
} {1 2 3 4 8 5 6 7}
do_test bind-15.2 {
  db eval {DELETE FROM t4}
  set VM [sqlite3_prepare db {
       INSERT INTO t4(a,b,c,d,e,f,g,h) VALUES(?,?,?,?,?,?,?,?)
  } -1 TAIL]
  sqlite3_bind_int $VM 1 1
  sqlite3_bind_int $VM 2 2
  sqlite3_bind_int $VM 3 3
  sqlite3_bind_int $VM 4 4
  sqlite3_bind_int $VM 5 5
  sqlite3_bind_int $VM 6 6
  sqlite3_bind_int $VM 7 7
  sqlite3_bind_int $VM 8 8
  sqlite3_step $VM
  sqlite3_finalize $VM
  db eval {SELECT * FROM t4}
} {1 2 3 4 5 6 7 8}
do_test bind-15.3 {
  db eval {DELETE FROM t4}
  set VM [sqlite3_prepare db {
       INSERT INTO t4(h,g,f,e,d,c,b,a) VALUES(?,?,?,?,?,?,?,?)
  } -1 TAIL]
  sqlite3_bind_int $VM 1 1
  sqlite3_bind_int $VM 2 2
  sqlite3_bind_int $VM 3 3
  sqlite3_bind_int $VM 4 4
  sqlite3_bind_int $VM 5 5
  sqlite3_bind_int $VM 6 6
  sqlite3_bind_int $VM 7 7
  sqlite3_bind_int $VM 8 8
  sqlite3_step $VM
  sqlite3_finalize $VM
  db eval {SELECT * FROM t4}
} {8 7 6 5 4 3 2 1}
do_test bind-15.4 {
  db eval {DELETE FROM t4}
  set VM [sqlite3_prepare db {
       INSERT INTO t4(a,b,c,d,e,f,g,h) VALUES(?,?,?,?4,?,?6,?,?)
  } -1 TAIL]
  sqlite3_bind_int $VM 1 1
  sqlite3_bind_int $VM 2 2
  sqlite3_bind_int $VM 3 3
  sqlite3_bind_int $VM 4 4
  sqlite3_bind_int $VM 5 5
  sqlite3_bind_int $VM 6 6
  sqlite3_bind_int $VM 7 7
  sqlite3_bind_int $VM 8 8
  sqlite3_step $VM
  sqlite3_finalize $VM
  db eval {SELECT * FROM t4}
} {1 2 3 4 5 6 7 8}

finish_test