SQLite4
Check-in [79197d57b4]
Not logged in

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

Overview
Comment:Change sqlite4_prepare() to return the number of bytes read from the input SQL script via an output variable (instead of returning a pointer to the next SQL statement within the buffer).
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 79197d57b4a6bffd58bd881148edf2968b084f2b
User & Date: dan 2013-05-10 19:19:07
Context
2013-05-18
19:42
Use the default sqlite4_mm object for malloc() and free(). check-in: e3280f4585 user: dan tags: trunk
2013-05-10
19:19
Change sqlite4_prepare() to return the number of bytes read from the input SQL script via an output variable (instead of returning a pointer to the next SQL statement within the buffer). check-in: 79197d57b4 user: dan tags: trunk
18:42
Change the sqlite4_exec() function to pass protected sqlite4_value objects to the callback instead of an array of nul-terminated strings. check-in: bbf3a54dcf user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to src/legacy.c.

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
..
46
47
48
49
50
51
52

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  sqlite4 *db,                /* The database on which the SQL executes */
  const char *zSql,           /* The SQL to be executed */
  int (*xCall)(void*,int,sqlite4_value**,const char**),  /* Callback function */
  void *pArg,                 /* First argument to xCall() */
  char **pzErrMsg             /* Write error messages here */
){
  int rc = SQLITE4_OK;        /* Return code */
  const char *zLeftover;      /* Tail of unprocessed SQL */
  int nRetry = 0;             /* Number of retry attempts */
  int bAbort = 0;             /* Set to true if callback returns non-zero */

  if( !sqlite4SafetyCheckOk(db) ) return SQLITE4_MISUSE_BKPT;
  if( zSql==0 ) zSql = "";

  sqlite4_mutex_enter(db->mutex);
................................................................................
  sqlite4Error(db, SQLITE4_OK, 0);

  /* Loop until we run out of SQL to execute, or the callback function
  ** returns non-zero, or an error occurs.  */
  while( zSql[0] && bAbort==0
     && (rc==SQLITE4_OK || (rc==SQLITE4_SCHEMA && (++nRetry)<2))
  ){

    int nCol;                     /* Number of returned columns */
    sqlite4_stmt *pStmt = 0;      /* The current SQL statement */
    const char **azCol = 0;       /* Names of result columns */
    sqlite4_value **apVal = 0;    /* Row of value objects */

    pStmt = 0;
    rc = sqlite4_prepare(db, zSql, -1, &pStmt, &zLeftover);
    assert( rc==SQLITE4_OK || pStmt==0 );
    if( rc!=SQLITE4_OK ){
      continue;
    }
    if( !pStmt ){
      /* this happens for a comment or white-space */
      zSql = zLeftover;
      continue;
    }

    nCol = sqlite4_column_count(pStmt);
    do {

      /* Step the statement. Then invoke the callback function if required */
................................................................................
      }

      if( bAbort || rc!=SQLITE4_ROW ){
        rc = sqlite4VdbeFinalize((Vdbe *)pStmt);
        pStmt = 0;
        if( rc!=SQLITE4_SCHEMA ){
          nRetry = 0;
          zSql = zLeftover;
          while( sqlite4Isspace(zSql[0]) ) zSql++;
        }
        assert( rc!=SQLITE4_ROW );
      }
    }while( rc==SQLITE4_ROW );

    sqlite4DbFree(db, azCol);







<







 







>






|






|







 







|







31
32
33
34
35
36
37

38
39
40
41
42
43
44
..
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  sqlite4 *db,                /* The database on which the SQL executes */
  const char *zSql,           /* The SQL to be executed */
  int (*xCall)(void*,int,sqlite4_value**,const char**),  /* Callback function */
  void *pArg,                 /* First argument to xCall() */
  char **pzErrMsg             /* Write error messages here */
){
  int rc = SQLITE4_OK;        /* Return code */

  int nRetry = 0;             /* Number of retry attempts */
  int bAbort = 0;             /* Set to true if callback returns non-zero */

  if( !sqlite4SafetyCheckOk(db) ) return SQLITE4_MISUSE_BKPT;
  if( zSql==0 ) zSql = "";

  sqlite4_mutex_enter(db->mutex);
................................................................................
  sqlite4Error(db, SQLITE4_OK, 0);

  /* Loop until we run out of SQL to execute, or the callback function
  ** returns non-zero, or an error occurs.  */
  while( zSql[0] && bAbort==0
     && (rc==SQLITE4_OK || (rc==SQLITE4_SCHEMA && (++nRetry)<2))
  ){
    int nUsed;                    /* Length of first SQL statement in zSql */
    int nCol;                     /* Number of returned columns */
    sqlite4_stmt *pStmt = 0;      /* The current SQL statement */
    const char **azCol = 0;       /* Names of result columns */
    sqlite4_value **apVal = 0;    /* Row of value objects */

    pStmt = 0;
    rc = sqlite4_prepare(db, zSql, -1, &pStmt, &nUsed);
    assert( rc==SQLITE4_OK || pStmt==0 );
    if( rc!=SQLITE4_OK ){
      continue;
    }
    if( !pStmt ){
      /* this happens for a comment or white-space */
      zSql += nUsed;
      continue;
    }

    nCol = sqlite4_column_count(pStmt);
    do {

      /* Step the statement. Then invoke the callback function if required */
................................................................................
      }

      if( bAbort || rc!=SQLITE4_ROW ){
        rc = sqlite4VdbeFinalize((Vdbe *)pStmt);
        pStmt = 0;
        if( rc!=SQLITE4_SCHEMA ){
          nRetry = 0;
          zSql += nUsed;
          while( sqlite4Isspace(zSql[0]) ) zSql++;
        }
        assert( rc!=SQLITE4_ROW );
      }
    }while( rc==SQLITE4_ROW );

    sqlite4DbFree(db, azCol);

Changes to src/prepare.c.

467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
...
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
...
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
...
654
655
656
657
658
659
660
661
662
663
664
665
666
667
*/
static int sqlite4Prepare(
  sqlite4 *db,              /* Database handle. */
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nBytes,               /* Length of zSql in bytes. */
  Vdbe *pReprepare,         /* VM being reprepared */
  sqlite4_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  const char **pzTail       /* OUT: End of parsed string */
){
  Parse *pParse;            /* Parsing context */
  char *zErrMsg = 0;        /* Error message */
  int rc = SQLITE4_OK;       /* Result code */
  int i;                    /* Loop counter */

  /* Allocate the parsing context */
................................................................................
  if( pParse->rc==SQLITE4_DONE ) pParse->rc = SQLITE4_OK;
  if( pParse->checkSchema ){
    schemaIsValid(pParse);
  }
  if( db->mallocFailed ){
    pParse->rc = SQLITE4_NOMEM;
  }
  if( pzTail ){
    *pzTail = pParse->zTail;
  }
  rc = pParse->rc;

#ifndef SQLITE4_OMIT_EXPLAIN
  if( rc==SQLITE4_OK && pParse->pVdbe && pParse->explain ){
    static const char * const azColName[] = {
       "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
................................................................................
}
static int sqlite4LockAndPrepare(
  sqlite4 *db,              /* Database handle. */
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nBytes,               /* Length of zSql in bytes. */
  Vdbe *pOld,               /* VM being reprepared */
  sqlite4_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  const char **pzTail       /* OUT: End of parsed string */
){
  int rc;
  assert( ppStmt!=0 );
  *ppStmt = 0;
  if( !sqlite4SafetyCheckOk(db) ){
    return SQLITE4_MISUSE_BKPT;
  }
  sqlite4_mutex_enter(db->mutex);
  rc = sqlite4Prepare(db, zSql, nBytes, pOld, ppStmt, pzTail);
  if( rc==SQLITE4_SCHEMA ){
    sqlite4_finalize(*ppStmt);
    rc = sqlite4Prepare(db, zSql, nBytes, pOld, ppStmt, pzTail);
  }
  sqlite4_mutex_leave(db->mutex);
  return rc;
}

/*
** Rerun the compilation of a statement after a schema change.
................................................................................
** occurs.
*/
int sqlite4_prepare(
  sqlite4 *db,              /* Database handle. */
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nBytes,               /* Length of zSql in bytes. */
  sqlite4_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  const char **pzTail       /* OUT: End of parsed string */
){
  int rc;
  rc = sqlite4LockAndPrepare(db,zSql,nBytes,0,ppStmt,pzTail);
  assert( rc==SQLITE4_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
  return rc;
}







|







 







|
|







 







|








|


|







 







|


|



467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
...
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
...
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
...
654
655
656
657
658
659
660
661
662
663
664
665
666
667
*/
static int sqlite4Prepare(
  sqlite4 *db,              /* Database handle. */
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nBytes,               /* Length of zSql in bytes. */
  Vdbe *pReprepare,         /* VM being reprepared */
  sqlite4_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  int *pnUsed               /* OUT: Bytes read from zSql */
){
  Parse *pParse;            /* Parsing context */
  char *zErrMsg = 0;        /* Error message */
  int rc = SQLITE4_OK;       /* Result code */
  int i;                    /* Loop counter */

  /* Allocate the parsing context */
................................................................................
  if( pParse->rc==SQLITE4_DONE ) pParse->rc = SQLITE4_OK;
  if( pParse->checkSchema ){
    schemaIsValid(pParse);
  }
  if( db->mallocFailed ){
    pParse->rc = SQLITE4_NOMEM;
  }
  if( pnUsed ){
    *pnUsed = (pParse->zTail-zSql);
  }
  rc = pParse->rc;

#ifndef SQLITE4_OMIT_EXPLAIN
  if( rc==SQLITE4_OK && pParse->pVdbe && pParse->explain ){
    static const char * const azColName[] = {
       "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
................................................................................
}
static int sqlite4LockAndPrepare(
  sqlite4 *db,              /* Database handle. */
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nBytes,               /* Length of zSql in bytes. */
  Vdbe *pOld,               /* VM being reprepared */
  sqlite4_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  int *pnUsed               /* OUT: Bytes read from zSql */
){
  int rc;
  assert( ppStmt!=0 );
  *ppStmt = 0;
  if( !sqlite4SafetyCheckOk(db) ){
    return SQLITE4_MISUSE_BKPT;
  }
  sqlite4_mutex_enter(db->mutex);
  rc = sqlite4Prepare(db, zSql, nBytes, pOld, ppStmt, pnUsed);
  if( rc==SQLITE4_SCHEMA ){
    sqlite4_finalize(*ppStmt);
    rc = sqlite4Prepare(db, zSql, nBytes, pOld, ppStmt, pnUsed);
  }
  sqlite4_mutex_leave(db->mutex);
  return rc;
}

/*
** Rerun the compilation of a statement after a schema change.
................................................................................
** occurs.
*/
int sqlite4_prepare(
  sqlite4 *db,              /* Database handle. */
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nBytes,               /* Length of zSql in bytes. */
  sqlite4_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  int *pnUsed               /* OUT: Bytes read from zSql */
){
  int rc;
  rc = sqlite4LockAndPrepare(db, zSql, nBytes, 0, ppStmt, pnUsed);
  assert( rc==SQLITE4_OK || ppStmt==0 || *ppStmt==0 );  /* VERIFY: F13021 */
  return rc;
}

Changes to src/shell.c.

760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
....
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091

1092
1093
1094
1095
1096
1097
1098
....
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131


static int shell_handle_row(
  struct callback_data *p,
  sqlite4_stmt *pStmt
){
  int nData = sqlite4_data_count(pStmt);
  int nCol = sqlite4_column_count(pStmt);
  int i;

  assert( nData>0 );

  switch( p->mode ){
    case MODE_Line: {
      int w = 5;
................................................................................
  const char *zScript,            /* SQL script to be evaluated */
  struct callback_data *pArg      /* Pointer to struct callback_data */
){
  int rc = SQLITE4_OK;            /* Return Code */
  const char *zSql = zScript;     /* Unexecuted portion of SQL script */

  while( zSql[0] && SQLITE4_OK==rc ){
    int bFirst = 1;
    const char *zLeftover;        /* Tail of unprocessed SQL */
    sqlite4_stmt *pStmt = 0;      /* Next statement to execute. */

    rc = sqlite4_prepare(db, zSql, -1, &pStmt, &zLeftover);
    if( rc!=SQLITE4_OK ) return rc;
    zSql = zLeftover;

    if( pStmt==0 ) continue;      /* A comment or whitespace */

    if( pArg->echoOn ){
      const char *zStmtSql = sqlite4_sql(pStmt);
      fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
    }

................................................................................
      display_stats(db, pStmt, pArg, 0);
    }

    /* Finalize the statement just executed. If this fails, save a 
    ** copy of the error message. Otherwise, set zSql to point to the
    ** next statement to execute. */
    rc = sqlite4_finalize(pStmt);
    zSql = zLeftover;
  } /* end while */

  return rc;
}


/*







<







 







|
<


|

<
>







 







<







760
761
762
763
764
765
766

767
768
769
770
771
772
773
....
1077
1078
1079
1080
1081
1082
1083
1084

1085
1086
1087
1088

1089
1090
1091
1092
1093
1094
1095
1096
....
1115
1116
1117
1118
1119
1120
1121

1122
1123
1124
1125
1126
1127
1128


static int shell_handle_row(
  struct callback_data *p,
  sqlite4_stmt *pStmt
){
  int nData = sqlite4_data_count(pStmt);

  int i;

  assert( nData>0 );

  switch( p->mode ){
    case MODE_Line: {
      int w = 5;
................................................................................
  const char *zScript,            /* SQL script to be evaluated */
  struct callback_data *pArg      /* Pointer to struct callback_data */
){
  int rc = SQLITE4_OK;            /* Return Code */
  const char *zSql = zScript;     /* Unexecuted portion of SQL script */

  while( zSql[0] && SQLITE4_OK==rc ){
    int nUsed;                    /* Bytes read from zSql */

    sqlite4_stmt *pStmt = 0;      /* Next statement to execute. */

    rc = sqlite4_prepare(db, zSql, -1, &pStmt, &nUsed);
    if( rc!=SQLITE4_OK ) return rc;

    zSql += nUsed;
    if( pStmt==0 ) continue;      /* A comment or whitespace */

    if( pArg->echoOn ){
      const char *zStmtSql = sqlite4_sql(pStmt);
      fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
    }

................................................................................
      display_stats(db, pStmt, pArg, 0);
    }

    /* Finalize the statement just executed. If this fails, save a 
    ** copy of the error message. Otherwise, set zSql to point to the
    ** next statement to execute. */
    rc = sqlite4_finalize(pStmt);

  } /* end while */

  return rc;
}


/*

Changes to src/sqlite.h.in.

1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
** the nByte-th byte, whichever comes first. If the caller knows
** that the supplied string is nul-terminated, then there is a small
** performance advantage to be gained by passing an nByte parameter that
** is equal to the number of bytes in the input string <i>including</i>
** the nul-terminator bytes as this saves SQLite from having to
** make a copy of the input string.
**
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
** past the end of the first SQL statement in zSql.  These routines only
** compile the first statement in zSql, so *pzTail is left pointing to
** what remains uncompiled.
**
** ^*ppStmt is left pointing to a compiled [prepared statement] that can be
** executed using [sqlite4_step()].  ^If there is an error, *ppStmt is set
** to NULL.  ^If the input text contains no SQL (if the input is an empty
** string or a comment) then *ppStmt is set to NULL.
** The calling procedure is responsible for deleting the compiled
** SQL statement using [sqlite4_finalize()] after it has finished with it.
** ppStmt may not be NULL.
**
** ^On success, the sqlite4_prepare() family of routines return [SQLITE4_OK];
** otherwise an [error code] is returned.
*/
int sqlite4_prepare(
  sqlite4 *db,            /* Database handle */
  const char *zSql,       /* SQL statement, UTF-8 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  sqlite4_stmt **ppStmt,  /* OUT: Statement handle */
  const char **pzTail
);

/*
** CAPIREF: Retrieving Statement SQL
**
** ^This interface can be used to retrieve a saved copy of the original
** SQL text used to create a [prepared statement] if that statement was







|
|
|
<




|
|
|
<









|







1689
1690
1691
1692
1693
1694
1695
1696
1697
1698

1699
1700
1701
1702
1703
1704
1705

1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
** the nByte-th byte, whichever comes first. If the caller knows
** that the supplied string is nul-terminated, then there is a small
** performance advantage to be gained by passing an nByte parameter that
** is equal to the number of bytes in the input string <i>including</i>
** the nul-terminator bytes as this saves SQLite from having to
** make a copy of the input string.
**
** ^If pnUsed is not NULL then *pnUsed is set to the number of bytes read
** from zSql. That is, the offset within zSql of the first byte past the
** end of the SQL statement compiled. 

**
** ^*ppStmt is left pointing to a compiled [prepared statement] that can be
** executed using [sqlite4_step()].  ^If there is an error, *ppStmt is set
** to NULL.  ^If the input text contains no SQL (if the input is an empty
** string or a comment) then *ppStmt is set to NULL. The calling procedure 
** is responsible for deleting the compiled SQL statement using 
** [sqlite4_finalize()] after it has finished with it. ppStmt may not be NULL.

**
** ^On success, the sqlite4_prepare() family of routines return [SQLITE4_OK];
** otherwise an [error code] is returned.
*/
int sqlite4_prepare(
  sqlite4 *db,            /* Database handle */
  const char *zSql,       /* SQL statement, UTF-8 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  sqlite4_stmt **ppStmt,  /* OUT: Statement handle */
  int *pnUsed             /* OUT: Number of bytes read from zSql */
);

/*
** CAPIREF: Retrieving Statement SQL
**
** ^This interface can be used to retrieve a saved copy of the original
** SQL text used to create a [prepared statement] if that statement was

Changes to src/tclsqlite.c.

761
762
763
764
765
766
767

768
769
770
771
772

773
774
775
776
777
778
779
...
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
    }
  }
  
  /* If no prepared statement was found. Compile the SQL text. Also allocate
  ** a new SqlPreparedStmt structure.  */
  if( pPreStmt==0 ){
    int nByte;


    if( SQLITE4_OK!=sqlite4_prepare(pDb->db, zSql, -1, &pStmt, pzOut) ){
      Tcl_SetObjResult(interp, dbTextToObj(sqlite4_errmsg(pDb->db)));
      return TCL_ERROR;
    }

    if( pStmt==0 ){
      if( SQLITE4_OK!=sqlite4_errcode(pDb->db) ){
        /* A compile-time error in the statement. */
        Tcl_SetObjResult(interp, dbTextToObj(sqlite4_errmsg(pDb->db)));
        return TCL_ERROR;
      }else{
        /* The statement was a no-op.  Continue to the next statement
................................................................................
    assert( pPreStmt==0 );
    nVar = sqlite4_bind_parameter_count(pStmt);
    nByte = sizeof(SqlPreparedStmt) + nVar*sizeof(Tcl_Obj *);
    pPreStmt = (SqlPreparedStmt*)Tcl_Alloc(nByte);
    memset(pPreStmt, 0, nByte);

    pPreStmt->pStmt = pStmt;
    pPreStmt->nSql = (*pzOut - zSql);
    pPreStmt->zSql = sqlite4_sql(pStmt);
    pPreStmt->apParm = (Tcl_Obj **)&pPreStmt[1];
#ifdef SQLITE4_TEST
    if( pPreStmt->zSql==0 ){
      char *zCopy = Tcl_Alloc(pPreStmt->nSql + 1);
      memcpy(zCopy, zSql, pPreStmt->nSql);
      zCopy[pPreStmt->nSql] = '\0';







>

|



>







 







|







761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
...
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
    }
  }
  
  /* If no prepared statement was found. Compile the SQL text. Also allocate
  ** a new SqlPreparedStmt structure.  */
  if( pPreStmt==0 ){
    int nByte;
    int nUsed;

    if( SQLITE4_OK!=sqlite4_prepare(pDb->db, zSql, -1, &pStmt, &nUsed) ){
      Tcl_SetObjResult(interp, dbTextToObj(sqlite4_errmsg(pDb->db)));
      return TCL_ERROR;
    }
    *pzOut = &zSql[nUsed];
    if( pStmt==0 ){
      if( SQLITE4_OK!=sqlite4_errcode(pDb->db) ){
        /* A compile-time error in the statement. */
        Tcl_SetObjResult(interp, dbTextToObj(sqlite4_errmsg(pDb->db)));
        return TCL_ERROR;
      }else{
        /* The statement was a no-op.  Continue to the next statement
................................................................................
    assert( pPreStmt==0 );
    nVar = sqlite4_bind_parameter_count(pStmt);
    nByte = sizeof(SqlPreparedStmt) + nVar*sizeof(Tcl_Obj *);
    pPreStmt = (SqlPreparedStmt*)Tcl_Alloc(nByte);
    memset(pPreStmt, 0, nByte);

    pPreStmt->pStmt = pStmt;
    pPreStmt->nSql = nUsed;
    pPreStmt->zSql = sqlite4_sql(pStmt);
    pPreStmt->apParm = (Tcl_Obj **)&pPreStmt[1];
#ifdef SQLITE4_TEST
    if( pPreStmt->zSql==0 ){
      char *zCopy = Tcl_Alloc(pPreStmt->nSql + 1);
      memcpy(zCopy, zSql, pPreStmt->nSql);
      zCopy[pPreStmt->nSql] = '\0';

Changes to test/test_main.c.

2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951


2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite4 *db;
  const char *zSql;
  int bytes;
  const char *zTail = 0;
  sqlite4_stmt *pStmt = 0;
  char zBuf[50];
  int rc;

  if( objc!=5 && objc!=4 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
       Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zSql = Tcl_GetString(objv[2]);
  if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;

  rc = sqlite4_prepare(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0);
  Tcl_ResetResult(interp);
  if( sqlite4TestErrCode(interp, db, rc) ) return TCL_ERROR;
  if( zTail && objc>=5 ){


    if( bytes>=0 ){
      bytes = bytes - (zTail-zSql);
    }
    if( strlen(zTail)<bytes ){
      bytes = strlen(zTail);
    }
    Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
  }
  if( rc!=SQLITE4_OK ){
    assert( pStmt==0 );
    sprintf(zBuf, "(%d) ", rc);
    Tcl_AppendResult(interp, zBuf, sqlite4_errmsg(db), 0);
    return TCL_ERROR;
  }







|













|


|
>
>

|

<
<
<
|







2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956



2957
2958
2959
2960
2961
2962
2963
2964
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite4 *db;
  const char *zSql;
  int bytes;
  int nUsed;
  sqlite4_stmt *pStmt = 0;
  char zBuf[50];
  int rc;

  if( objc!=5 && objc!=4 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
       Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zSql = Tcl_GetString(objv[2]);
  if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;

  rc = sqlite4_prepare(db, zSql, bytes, &pStmt, objc>=5 ? &nUsed : 0);
  Tcl_ResetResult(interp);
  if( sqlite4TestErrCode(interp, db, rc) ) return TCL_ERROR;
  if( objc>=5 ){
    const char *zTail = &zSql[nUsed];
    int nTail = -1;
    if( bytes>=0 ){
      nTail = bytes - nUsed;
    }



    Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, nTail), 0);
  }
  if( rc!=SQLITE4_OK ){
    assert( pStmt==0 );
    sprintf(zBuf, "(%d) ", rc);
    Tcl_AppendResult(interp, zBuf, sqlite4_errmsg(db), 0);
    return TCL_ERROR;
  }

Changes to test/test_thread.c.

490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
...
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
...
557
558
559
560
561
562
563
564
565
566
567
568
569
570


571
572
573
574
575
576
577
578
579
580
581
** system may become deadlocked.
*/
int sqlite4_blocking_prepare(
  sqlite4 *db,              /* Database handle. */
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nSql,                 /* Length of zSql in bytes. */
  sqlite4_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  const char **pz           /* OUT: End of parsed string */
){
  int rc;
  while( SQLITE4_LOCKED==(rc = sqlite4_prepare(db, zSql, nSql, ppStmt, pz)) ){
    rc = wait_for_unlock_notify(db);
    if( rc!=SQLITE4_OK ) break;
  }
  return rc;
}
/* END_SQLITE4_BLOCKING_STEP */

................................................................................
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite4 *db;
  const char *zSql;
  int bytes;
  const char *zTail = 0;
  sqlite4_stmt *pStmt = 0;
  char zBuf[50];
  int rc;
  int isBlocking = !(clientData==0);

  if( objc!=5 && objc!=4 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
................................................................................
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zSql = Tcl_GetString(objv[2]);
  if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;

  if( isBlocking ){
    rc = sqlite4_blocking_prepare(db, zSql, bytes, &pStmt, &zTail);
  }else{
    rc = sqlite4_prepare(db, zSql, bytes, &pStmt, &zTail);
  }

  assert(rc==SQLITE4_OK || pStmt==0);
  if( zTail && objc>=5 ){


    if( bytes>=0 ){
      bytes = bytes - (zTail-zSql);
    }
    Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
  }
  if( rc!=SQLITE4_OK ){
    assert( pStmt==0 );
    sprintf(zBuf, "%s ", (char *)sqlite4TestErrorName(rc));
    Tcl_AppendResult(interp, zBuf, sqlite4_errmsg(db), 0);
    return TCL_ERROR;
  }







|


|







 







|







 







|

|



|
>
>

|

|







490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
...
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
...
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
** system may become deadlocked.
*/
int sqlite4_blocking_prepare(
  sqlite4 *db,              /* Database handle. */
  const char *zSql,         /* UTF-8 encoded SQL statement. */
  int nSql,                 /* Length of zSql in bytes. */
  sqlite4_stmt **ppStmt,    /* OUT: A pointer to the prepared statement */
  int *pn                   /* OUT: Bytes read from zSql */
){
  int rc;
  while( SQLITE4_LOCKED==(rc = sqlite4_prepare(db, zSql, nSql, ppStmt, pn)) ){
    rc = wait_for_unlock_notify(db);
    if( rc!=SQLITE4_OK ) break;
  }
  return rc;
}
/* END_SQLITE4_BLOCKING_STEP */

................................................................................
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite4 *db;
  const char *zSql;
  int bytes;
  int nUsed;
  sqlite4_stmt *pStmt = 0;
  char zBuf[50];
  int rc;
  int isBlocking = !(clientData==0);

  if( objc!=5 && objc!=4 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
................................................................................
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  zSql = Tcl_GetString(objv[2]);
  if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;

  if( isBlocking ){
    rc = sqlite4_blocking_prepare(db, zSql, bytes, &pStmt, &nUsed);
  }else{
    rc = sqlite4_prepare(db, zSql, bytes, &pStmt, &nUsed);
  }

  assert(rc==SQLITE4_OK || pStmt==0);
  if( objc>=5 ){
    const char *zTail = zSql[nUsed];
    int nTail = -1;
    if( bytes>=0 ){
      nTail = bytes - nUsed;
    }
    Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, nTail), 0);
  }
  if( rc!=SQLITE4_OK ){
    assert( pStmt==0 );
    sprintf(zBuf, "%s ", (char *)sqlite4TestErrorName(rc));
    Tcl_AppendResult(interp, zBuf, sqlite4_errmsg(db), 0);
    return TCL_ERROR;
  }