/ Check-in [3787563e]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Readded the sqlite3_open_v2() interface. No test cases yet. Additional progress toward adding mutexes to all interfaces. (CVS 4261)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3787563e90d7210d349ee36484c3f008c955552e
User & Date: drh 2007-08-21 15:13:19
Context
2007-08-21
16:15
Adding more thread locking code. This is an incremental check-in. (CVS 4262) check-in: 7428732b user: drh tags: trunk
15:13
Readded the sqlite3_open_v2() interface. No test cases yet. Additional progress toward adding mutexes to all interfaces. (CVS 4261) check-in: 3787563e user: drh tags: trunk
14:27
Delay opening temporary pager files until they are first written. (CVS 4260) check-in: 3fb97a63 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/loadext.c.

352
353
354
355
356
357
358

359
360
361
362
363
364
365



366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381

382
383
384
385
386
387


388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  }else{
    db->flags &= ~SQLITE_LoadExtension;
  }
  return SQLITE_OK;
}

/*

** A list of automatically loaded extensions.
**
** This list is shared across threads, so be sure to hold the
** mutex while accessing or changing it.
*/
static int nAutoExtension = 0;
static void **aAutoExtension = 0;





/*
** Register a statically linked extension that is automatically
** loaded by every new database connection.
*/
int sqlite3_auto_extension(void *xInit){
  int i;
  int rc = SQLITE_OK;
  sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
  sqlite3_mutex_enter(mutex);
  for(i=0; i<nAutoExtension; i++){
    if( aAutoExtension[i]==xInit ) break;
  }
  if( i==nAutoExtension ){
    int nByte = (++nAutoExtension)*sizeof(aAutoExtension[0]);

    aAutoExtension = sqlite3_realloc(aAutoExtension, nByte);
    if( aAutoExtension==0 ){
      nAutoExtension = 0;
      rc = SQLITE_NOMEM;
    }else{
      aAutoExtension[nAutoExtension-1] = xInit;


    }
  }
  sqlite3_mutex_leave(mutex);
  assert( (rc&0xff)==rc );
  return rc;
}

/*
** Reset the automatic extension loading mechanism.
*/
void sqlite3_reset_auto_extension(void){
  sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
  sqlite3_mutex_enter(mutex);
  sqlite3_free(aAutoExtension);
  aAutoExtension = 0;
  nAutoExtension = 0;
  sqlite3_mutex_leave(mutex);
}

/*
** Load all automatic extensions.
*/
int sqlite3AutoLoadExtensions(sqlite3 *db){
  int i;
  int go = 1;
  int rc = SQLITE_OK;
  int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);

  if( nAutoExtension==0 ){
    /* Common case: early out without every having to acquire a mutex */
    return SQLITE_OK;
  }
  for(i=0; go; i++){
    char *zErrmsg = 0;
    sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
    sqlite3_mutex_enter(mutex);
    if( i>=nAutoExtension ){
      xInit = 0;
      go = 0;
    }else{
      xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
              aAutoExtension[i];
    }
    sqlite3_mutex_leave(mutex);
    if( xInit && xInit(db, &zErrmsg, &sqlite3_apis) ){
      sqlite3Error(db, SQLITE_ERROR,
            "automatic extension loading failed: %s", zErrmsg);
      go = 0;
      rc = SQLITE_ERROR;
    }
  }
  return rc;
}

#endif /* SQLITE_OMIT_LOAD_EXTENSION */







>
|

|
|

<
|
>
>
>











|
|

|
|
>
|
<
|


|
>
>













|
|
|












|







|




|













352
353
354
355
356
357
358
359
360
361
362
363
364

365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386

387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
  }else{
    db->flags &= ~SQLITE_LoadExtension;
  }
  return SQLITE_OK;
}

/*
** The following object holds the list of automatically loaded
** extensions.
**
** This list is shared across threads.  The SQLITE_MUTEX_STATIC_MASTER
** mutex must be held while accessing this list.
*/

static struct {
  int nExt;        /* Number of entries in aExt[] */          
  void **aExt;     /* Pointers to the extension init functions */
} autoext = { 0, 0 };


/*
** Register a statically linked extension that is automatically
** loaded by every new database connection.
*/
int sqlite3_auto_extension(void *xInit){
  int i;
  int rc = SQLITE_OK;
  sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
  sqlite3_mutex_enter(mutex);
  for(i=0; i<autoext.nExt; i++){
    if( autoext.aExt[i]==xInit ) break;
  }
  if( i==autoext.nExt ){
    int nByte = (autoext.nExt+1)*sizeof(autoext.aExt[0]);
    void **aNew;
    aNew = sqlite3_realloc(autoext.aExt, nByte);

    if( aNew==0 ){
      rc = SQLITE_NOMEM;
    }else{
      autoext.aExt = aNew;
      autoext.aExt[autoext.nExt] = xInit;
      autoext.nExt++;
    }
  }
  sqlite3_mutex_leave(mutex);
  assert( (rc&0xff)==rc );
  return rc;
}

/*
** Reset the automatic extension loading mechanism.
*/
void sqlite3_reset_auto_extension(void){
  sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
  sqlite3_mutex_enter(mutex);
  sqlite3_free(autoext.aExt);
  autoext.aExt = 0;
  autoext.nExt = 0;
  sqlite3_mutex_leave(mutex);
}

/*
** Load all automatic extensions.
*/
int sqlite3AutoLoadExtensions(sqlite3 *db){
  int i;
  int go = 1;
  int rc = SQLITE_OK;
  int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);

  if( autoext.nExt==0 ){
    /* Common case: early out without every having to acquire a mutex */
    return SQLITE_OK;
  }
  for(i=0; go; i++){
    char *zErrmsg = 0;
    sqlite3_mutex *mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
    sqlite3_mutex_enter(mutex);
    if( i>=autoext.nExt ){
      xInit = 0;
      go = 0;
    }else{
      xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
              autoext.aExt[i];
    }
    sqlite3_mutex_leave(mutex);
    if( xInit && xInit(db, &zErrmsg, &sqlite3_apis) ){
      sqlite3Error(db, SQLITE_ERROR,
            "automatic extension loading failed: %s", zErrmsg);
      go = 0;
      rc = SQLITE_ERROR;
    }
  }
  return rc;
}

#endif /* SQLITE_OMIT_LOAD_EXTENSION */

Changes to src/main.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
114
115
116
117
118
119
120

121
122
123
124
125
126
127
...
214
215
216
217
218
219
220


221
222
223
224
225
226
227
...
886
887
888
889
890
891
892
893


894
895
896
897
898
899
900
901





902
903
904
905
906
907
908
909
....
1037
1038
1039
1040
1041
1042
1043
1044









1045
1046
1047
1048
1049
1050
1051
....
1059
1060
1061
1062
1063
1064
1065
1066

1067
1068
1069
1070
1071
1072
1073
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.390 2007/08/21 10:44:16 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The version of the library
*/
................................................................................

  if( !db ){
    return SQLITE_OK;
  }
  if( sqlite3SafetyCheck(db) ){
    return SQLITE_MISUSE;
  }


#ifdef SQLITE_SSE
  {
    extern void sqlite3SseCleanup(sqlite3*);
    sqlite3SseCleanup(db);
  }
#endif 
................................................................................
  ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
  ** So it needs to be freed here. Todo: Why not roll the temp schema into
  ** the same sqliteMalloc() as the one that allocates the database 
  ** structure?
  */
  sqlite3_free(db->aDb[1].pSchema);
  sqlite3_vfs_release(db->pVfs);


  sqlite3_free(db);
  return SQLITE_OK;
}

/*
** Rollback all database files.
*/
................................................................................
/*
** This routine does the work of opening a database on behalf of
** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"  
** is UTF-8 encoded.
*/
static int openDatabase(
  const char *zFilename, /* Database filename UTF-8 encoded */
  sqlite3 **ppDb         /* OUT: Returned database handle */


){
  sqlite3 *db;
  int rc;
  CollSeq *pColl;

  /* Allocate the sqlite data structure */
  db = sqlite3MallocZero( sizeof(sqlite3) );
  if( db==0 ) goto opendb_out;





  db->pVfs = sqlite3_vfs_find(0);
  db->errMask = 0xff;
  db->priorNewRowid = 0;
  db->magic = SQLITE_MAGIC_BUSY;
  db->nDb = 2;
  db->aDb = db->aDbStatic;
  db->autoCommit = 1;
  db->flags |= SQLITE_ShortColNames
................................................................................
/*
** Open a new database handle.
*/
int sqlite3_open(
  const char *zFilename, 
  sqlite3 **ppDb 
){
  return openDatabase(zFilename, ppDb);









}

#ifndef SQLITE_OMIT_UTF16
/*
** Open a new database handle.
*/
int sqlite3_open16(
................................................................................
  assert( zFilename );
  assert( ppDb );
  *ppDb = 0;
  pVal = sqlite3ValueNew(0);
  sqlite3ValueSetStr(0, pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC);
  zFilename8 = sqlite3ValueText(0, pVal, SQLITE_UTF8);
  if( zFilename8 ){
    rc = openDatabase(zFilename8, ppDb);

    if( rc==SQLITE_OK && *ppDb ){
      rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
      if( rc!=SQLITE_OK ){
        sqlite3_close(*ppDb);
        *ppDb = 0;
      }
    }







|







 







>







 







>
>







 







|
>
>








>
>
>
>
>
|







 







|
>
>
>
>
>
>
>
>
>







 







|
>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
...
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
....
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
....
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.391 2007/08/21 15:13:19 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The version of the library
*/
................................................................................

  if( !db ){
    return SQLITE_OK;
  }
  if( sqlite3SafetyCheck(db) ){
    return SQLITE_MISUSE;
  }
  sqlite3_mutex_enter(db->mutex);

#ifdef SQLITE_SSE
  {
    extern void sqlite3SseCleanup(sqlite3*);
    sqlite3SseCleanup(db);
  }
#endif 
................................................................................
  ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
  ** So it needs to be freed here. Todo: Why not roll the temp schema into
  ** the same sqliteMalloc() as the one that allocates the database 
  ** structure?
  */
  sqlite3_free(db->aDb[1].pSchema);
  sqlite3_vfs_release(db->pVfs);
  sqlite3_mutex_leave(db->mutex);
  sqlite3_mutex_free(db->mutex);
  sqlite3_free(db);
  return SQLITE_OK;
}

/*
** Rollback all database files.
*/
................................................................................
/*
** This routine does the work of opening a database on behalf of
** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"  
** is UTF-8 encoded.
*/
static int openDatabase(
  const char *zFilename, /* Database filename UTF-8 encoded */
  sqlite3 **ppDb,        /* OUT: Returned database handle */
  unsigned flags,        /* Operational flags */
  const char *zVfs       /* Name of the VFS to use */
){
  sqlite3 *db;
  int rc;
  CollSeq *pColl;

  /* Allocate the sqlite data structure */
  db = sqlite3MallocZero( sizeof(sqlite3) );
  if( db==0 ) goto opendb_out;
  db->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
  if( db->mutex==0 ){
    db->mallocFailed = 1;
    goto opendb_out;
  }
  db->pVfs = sqlite3_vfs_find(zVfs);
  db->errMask = 0xff;
  db->priorNewRowid = 0;
  db->magic = SQLITE_MAGIC_BUSY;
  db->nDb = 2;
  db->aDb = db->aDbStatic;
  db->autoCommit = 1;
  db->flags |= SQLITE_ShortColNames
................................................................................
/*
** Open a new database handle.
*/
int sqlite3_open(
  const char *zFilename, 
  sqlite3 **ppDb 
){
  return openDatabase(zFilename, ppDb,
                      SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
}
int sqlite3_open_v2(
  const void *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb,         /* OUT: SQLite db handle */
  int flags,              /* Flags */
  const char *zVfs        /* Name of VFS module to use */
){
  return openDatabase(filename, ppDb, flags, zVfs);
}

#ifndef SQLITE_OMIT_UTF16
/*
** Open a new database handle.
*/
int sqlite3_open16(
................................................................................
  assert( zFilename );
  assert( ppDb );
  *ppDb = 0;
  pVal = sqlite3ValueNew(0);
  sqlite3ValueSetStr(0, pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC);
  zFilename8 = sqlite3ValueText(0, pVal, SQLITE_UTF8);
  if( zFilename8 ){
    rc = openDatabase(zFilename8, ppDb,
                      SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
    if( rc==SQLITE_OK && *ppDb ){
      rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
      if( rc!=SQLITE_OK ){
        sqlite3_close(*ppDb);
        *ppDb = 0;
      }
    }

Changes to src/sqlite.h.in.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
1615
1616
1617
1618
1619
1620
1621




1622
1623
1624
1625
1626
1627
1628
....
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
....
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
** on how SQLite interfaces are suppose to operate.
**
** The name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
** @(#) $Id: sqlite.h.in,v 1.231 2007/08/20 22:48:43 drh Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
................................................................................
** with one, so the value returned is the number of parameters.  However
** if the same host parameter name is used multiple times, each occurrance
** is given the same number, so the value returned in that case is the number
** of unique host parameter names.  If host parameters of the form "?NNN"
** are used (where NNN is an integer) then there might be gaps in the
** numbering and the value returned by this interface is the index of the
** host parameter with the largest index value.




*/
int sqlite3_bind_parameter_count(sqlite3_stmt*);

/*
** CAPI3REF: Name Of A Host Parameter
**
** This routine returns a pointer to the name of the n-th parameter in a 
................................................................................
**
** The first parameter should be a copy of the 
** [sqlite3_context | SQL function context] that is the first
** parameter to the callback routine that implements the aggregate
** function.
**
** This routine must be called from the same thread in which
** the aggregate SQL function was originally invoked.
*/
void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);

/*
** CAPI3REF: User Data For Functions
**
** The pUserData parameter to the [sqlite3_create_function()]
................................................................................
int sqlite3_enable_load_extension(sqlite3 *db, int onoff);

/*
** CAPI3REF: Make Arrangements To Automatically Load An Extension
**
** Register an extension entry point that is automatically invoked
** whenever a new database connection is opened using
** [sqlite3_open()] or [sqlite3_open16()].
**
** This API can be invoked at program startup in order to register
** one or more statically linked extensions that will be available
** to all new database connections.
**
** Duplicate extensions are detected so calling this routine multiple
** times with the same extension is harmless.







|







 







>
>
>
>







 







|







 







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
....
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
....
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
** on how SQLite interfaces are suppose to operate.
**
** The name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
** @(#) $Id: sqlite.h.in,v 1.232 2007/08/21 15:13:19 drh Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
................................................................................
** with one, so the value returned is the number of parameters.  However
** if the same host parameter name is used multiple times, each occurrance
** is given the same number, so the value returned in that case is the number
** of unique host parameter names.  If host parameters of the form "?NNN"
** are used (where NNN is an integer) then there might be gaps in the
** numbering and the value returned by this interface is the index of the
** host parameter with the largest index value.
**
** The prepared statement must not not be [sqlite3_finalize | finalized]
** prior to this routine returnning.  Otherwise the results are undefined
** and probably undesirable.
*/
int sqlite3_bind_parameter_count(sqlite3_stmt*);

/*
** CAPI3REF: Name Of A Host Parameter
**
** This routine returns a pointer to the name of the n-th parameter in a 
................................................................................
**
** The first parameter should be a copy of the 
** [sqlite3_context | SQL function context] that is the first
** parameter to the callback routine that implements the aggregate
** function.
**
** This routine must be called from the same thread in which
** the aggregate SQL function is running.
*/
void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);

/*
** CAPI3REF: User Data For Functions
**
** The pUserData parameter to the [sqlite3_create_function()]
................................................................................
int sqlite3_enable_load_extension(sqlite3 *db, int onoff);

/*
** CAPI3REF: Make Arrangements To Automatically Load An Extension
**
** Register an extension entry point that is automatically invoked
** whenever a new database connection is opened using
** [sqlite3_open()], [sqlite3_open16()], or [sqlite3_open_v2()].
**
** This API can be invoked at program startup in order to register
** one or more statically linked extensions that will be available
** to all new database connections.
**
** Duplicate extensions are detected so calling this routine multiple
** times with the same extension is harmless.

Changes to src/vdbeapi.c.

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
...
756
757
758
759
760
761
762

763
764
765
766

767
768
769
770
771
772
773
774

775
776
777
778

779
780
781



782


783
784
785
786
787
788
789
...
800
801
802
803
804
805
806

807
808
809
810

811
812
813
814
815

816
817
818
819

820
821
822
823
824
825
826
...
832
833
834
835
836
837
838


839
840
841
842
843
844
845
846
847


848
849
850
851
852
853
854
  return SQLITE_OK;
}

/*
** Bind a text or BLOB value.
*/
static int bindText(
  sqlite3_stmt *pStmt, 
  int i, 
  const void *zData, 
  int nData, 
  void (*xDel)(void*),
  int encoding
){
  Vdbe *p = (Vdbe *)pStmt;
  Mem *pVar;
  int rc;





  rc = vdbeUnbind(p, i);
  if( rc || zData==0 ){
    return rc;
  }
  pVar = &p->aVar[i-1];
  rc = sqlite3VdbeMemSetStr(0, pVar, zData, nData, encoding, xDel);
  if( rc==SQLITE_OK && encoding!=0 ){
    rc = sqlite3VdbeChangeEncoding(p->db, pVar, ENC(p->db));
  }

  sqlite3Error(p->db, rc, 0);
  return sqlite3ApiExit(p->db, rc);


}


/*
** Bind a blob value to an SQL statement variable.
*/
int sqlite3_bind_blob(
................................................................................
  void (*xDel)(void*)
){
  return bindText(pStmt, i, zData, nData, xDel, 0);
}
int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;

  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
  }

  return rc;
}
int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
  return sqlite3_bind_int64(p, i, (i64)iValue);
}
int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;

  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
  }

  return rc;
}
int sqlite3_bind_null(sqlite3_stmt* p, int i){



  return vdbeUnbind((Vdbe *)p, i);


}
int sqlite3_bind_text( 
  sqlite3_stmt *pStmt, 
  int i, 
  const char *zData, 
  int nData, 
  void (*xDel)(void*)
................................................................................
){
  return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
}
#endif /* SQLITE_OMIT_UTF16 */
int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;

  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    rc = sqlite3VdbeMemCopy(0, &p->aVar[i-1], pValue);
  }

  return rc;
}
int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;

  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
  }

  return rc;
}

/*
** Return the number of wildcards that can be potentially bound to.
** This routine is added to support DBD::SQLite.  
*/
................................................................................
/*
** Create a mapping from variable numbers to variable names
** in the Vdbe.azVar[] array, if such a mapping does not already
** exist.
*/
static void createVarMap(Vdbe *p){
  if( !p->okVar ){


    int j;
    Op *pOp;
    for(j=0, pOp=p->aOp; j<p->nOp; j++, pOp++){
      if( pOp->opcode==OP_Variable ){
        assert( pOp->p1>0 && pOp->p1<=p->nVar );
        p->azVar[pOp->p1-1] = pOp->p3;
      }
    }
    p->okVar = 1;


  }
}

/*
** Return the name of a wildcard parameter.  Return NULL if the index
** is out of range or if the wildcard is unnamed.
**







|
|
|
|
|
|





>
>
>
>





|



<

|
>
>







 







>




>








>




>


|
>
>
>
|
>
>







 







>




>





>




>







 







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







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
...
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
...
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
...
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
  return SQLITE_OK;
}

/*
** Bind a text or BLOB value.
*/
static int bindText(
  sqlite3_stmt *pStmt,   /* The statement to bind against */
  int i,                 /* Index of the parameter to bind */
  const void *zData,     /* Pointer to the data to be bound */
  int nData,             /* Number of bytes of data to be bound */
  void (*xDel)(void*),   /* Destructor for the data */
  int encoding           /* Encoding for the data */
){
  Vdbe *p = (Vdbe *)pStmt;
  Mem *pVar;
  int rc;

  if( p==0 ){
    return SQLITE_MISUSE;
  }
  sqlite3_mutex_enter(p->db->mutex);
  rc = vdbeUnbind(p, i);
  if( rc || zData==0 ){
    return rc;
  }
  pVar = &p->aVar[i-1];
  rc = sqlite3VdbeMemSetStr(p->db, pVar, zData, nData, encoding, xDel);
  if( rc==SQLITE_OK && encoding!=0 ){
    rc = sqlite3VdbeChangeEncoding(p->db, pVar, ENC(p->db));
  }

  sqlite3Error(p->db, rc, 0);
  rc = sqlite3ApiExit(p->db, rc);
  sqlite3_mutex_leave(p->db->mutex);
  return rc;
}


/*
** Bind a blob value to an SQL statement variable.
*/
int sqlite3_bind_blob(
................................................................................
  void (*xDel)(void*)
){
  return bindText(pStmt, i, zData, nData, xDel, 0);
}
int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;
  sqlite3_mutex_enter(p->db->mutex);
  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
  }
  sqlite3_mutex_leave(p->db->mutex);
  return rc;
}
int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
  return sqlite3_bind_int64(p, i, (i64)iValue);
}
int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;
  sqlite3_mutex_enter(p->db->mutex);
  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
  }
  sqlite3_mutex_leave(p->db->mutex);
  return rc;
}
int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
  int rc;
  Vdbe *p = (Vdbe*)pStmt;
  sqlite3_mutex_enter(p->db->mutex);
  rc = vdbeUnbind(p, i);
  sqlite3_mutex_leave(p->db->mutex);
  return rc;
}
int sqlite3_bind_text( 
  sqlite3_stmt *pStmt, 
  int i, 
  const char *zData, 
  int nData, 
  void (*xDel)(void*)
................................................................................
){
  return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
}
#endif /* SQLITE_OMIT_UTF16 */
int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;
  sqlite3_mutex_enter(p->db->mutex);
  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    rc = sqlite3VdbeMemCopy(0, &p->aVar[i-1], pValue);
  }
  sqlite3_mutex_leave(p->db->mutex);
  return rc;
}
int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
  int rc;
  Vdbe *p = (Vdbe *)pStmt;
  sqlite3_mutex_enter(p->db->mutex);
  rc = vdbeUnbind(p, i);
  if( rc==SQLITE_OK ){
    sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
  }
  sqlite3_mutex_leave(p->db->mutex);
  return rc;
}

/*
** Return the number of wildcards that can be potentially bound to.
** This routine is added to support DBD::SQLite.  
*/
................................................................................
/*
** Create a mapping from variable numbers to variable names
** in the Vdbe.azVar[] array, if such a mapping does not already
** exist.
*/
static void createVarMap(Vdbe *p){
  if( !p->okVar ){
    sqlite3_mutex_enter(p->db->mutex);
    if( !p->okVar ){
      int j;
      Op *pOp;
      for(j=0, pOp=p->aOp; j<p->nOp; j++, pOp++){
        if( pOp->opcode==OP_Variable ){
          assert( pOp->p1>0 && pOp->p1<=p->nVar );
          p->azVar[pOp->p1-1] = pOp->p3;
        }
      }
      p->okVar = 1;
    }
    sqlite3_mutex_leave(p->db->mutex);
  }
}

/*
** Return the name of a wildcard parameter.  Return NULL if the index
** is out of range or if the wildcard is unnamed.
**

Changes to src/vdbeblob.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
26
27
28
29
30
31
32

33
34
35
36
37
38
39
..
83
84
85
86
87
88
89

90
91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
...
215
216
217
218
219
220
221

222
223
224
225
226
227
228
229
230
231
232
233
234
235


236
237
238
239
240
241
242
243
244
245
246
247





248
249



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270

271







272
273
274
275

276
277
278
279
280
281
282
283
284
285


286
287
288
289
290
291
292
...
297
298
299
300
301
302
303



304
305
306
307
308
309
310
**    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.12 2007/08/16 04:30:41 drh Exp $
*/

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

#ifndef SQLITE_OMIT_INCRBLOB

................................................................................
typedef struct Incrblob Incrblob;
struct Incrblob {
  int flags;              /* Copy of "flags" passed to sqlite3_blob_open() */
  int nByte;              /* Size of open blob, in bytes */
  int iOffset;            /* Byte offset of blob in cursor data */
  BtCursor *pCsr;         /* Cursor pointing at blob row */
  sqlite3_stmt *pStmt;    /* Statement holding cursor open */

};

/*
** Open a blob handle.
*/
int sqlite3_blob_open(
  sqlite3* db,            /* The database connection */
................................................................................
  };

  Vdbe *v = 0;
  int rc = SQLITE_OK;
  char zErr[128];

  zErr[0] = 0;

  do {
    Parse sParse;
    Table *pTab;

    memset(&sParse, 0, sizeof(Parse));
    sParse.db = db;

    rc = sqlite3SafetyOn(db);
    if( rc!=SQLITE_OK ){

      return rc;
    }

    pTab = sqlite3LocateTable(&sParse, zTable, zDb);
    if( !pTab ){
      if( sParse.zErrMsg ){
        sqlite3_snprintf(sizeof(zErr), zErr, "%s", sParse.zErrMsg);
................................................................................
    }
    pBlob->flags = flags;
    pBlob->pCsr =  v->apCsr[0]->pCursor;
    sqlite3BtreeCacheOverflow(pBlob->pCsr);
    pBlob->pStmt = (sqlite3_stmt *)v;
    pBlob->iOffset = v->apCsr[0]->aOffset[iCol];
    pBlob->nByte = sqlite3VdbeSerialTypeLen(type);

    *ppBlob = (sqlite3_blob *)pBlob;
    rc = SQLITE_OK;
  }else if( rc==SQLITE_OK ){
    sqlite3_snprintf(sizeof(zErr), zErr, "no such rowid: %lld", iRow);
    rc = SQLITE_ERROR;
  }

blob_open_out:
  zErr[sizeof(zErr)-1] = '\0';
  if( rc!=SQLITE_OK || db->mallocFailed ){
    sqlite3_finalize((sqlite3_stmt *)v);
  }
  sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr));
  return sqlite3ApiExit(db, rc);


}

/*
** Close a blob handle that was previously created using
** sqlite3_blob_open().
*/
int sqlite3_blob_close(sqlite3_blob *pBlob){
  Incrblob *p = (Incrblob *)pBlob;
  sqlite3_stmt *pStmt = p->pStmt;
  sqlite3_free(p);
  return sqlite3_finalize(pStmt);
}










static int blobReadWrite(
  sqlite3_blob *pBlob, 
  void *z, 
  int n, 
  int iOffset, 
  int (*xCall)(BtCursor*, u32, u32, void*)
){
  int rc;
  Incrblob *p = (Incrblob *)pBlob;
  Vdbe *v = (Vdbe *)(p->pStmt);
  sqlite3 *db;  

  /* If there is no statement handle, then the blob-handle has
  ** already been invalidated. Return SQLITE_ABORT in this case.
  */
  if( !v ) return SQLITE_ABORT;

  /* Request is out of range. Return a transient error. */
  if( (iOffset+n)>p->nByte ){
    return SQLITE_ERROR;
  }









  /* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is
  ** returned, clean-up the statement handle.
  */
  db = v->db;

  rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
  if( rc==SQLITE_ABORT ){
    sqlite3VdbeFinalize(v);
    p->pStmt = 0;
  }else{
    db->errCode = rc;
    v->rc = rc;
  }

  return sqlite3ApiExit(db, rc);


}

/*
** Read data from a blob handle.
*/
int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
  return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData);
................................................................................
*/
int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
  return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData);
}

/*
** Query a blob handle for the size of the data.



*/
int sqlite3_blob_bytes(sqlite3_blob *pBlob){
  Incrblob *p = (Incrblob *)pBlob;
  return p->nByte;
}

#endif /* #ifndef SQLITE_OMIT_INCRBLOB */







|







 







>







 







>









>







 







>













|
>
>








|
|
|
|
>
>
>
>
>
|

>
>
>









|
|
<
<
<
<
<





>

>
>
>
>
>
>
>
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
>
>







 







>
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
..
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
...
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274





275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291

292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
...
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
**    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.13 2007/08/21 15:13:19 drh Exp $
*/

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

#ifndef SQLITE_OMIT_INCRBLOB

................................................................................
typedef struct Incrblob Incrblob;
struct Incrblob {
  int flags;              /* Copy of "flags" passed to sqlite3_blob_open() */
  int nByte;              /* Size of open blob, in bytes */
  int iOffset;            /* Byte offset of blob in cursor data */
  BtCursor *pCsr;         /* Cursor pointing at blob row */
  sqlite3_stmt *pStmt;    /* Statement holding cursor open */
  sqlite3 *db;            /* The associated database */
};

/*
** Open a blob handle.
*/
int sqlite3_blob_open(
  sqlite3* db,            /* The database connection */
................................................................................
  };

  Vdbe *v = 0;
  int rc = SQLITE_OK;
  char zErr[128];

  zErr[0] = 0;
  sqlite3_mutex_enter(db->mutex);
  do {
    Parse sParse;
    Table *pTab;

    memset(&sParse, 0, sizeof(Parse));
    sParse.db = db;

    rc = sqlite3SafetyOn(db);
    if( rc!=SQLITE_OK ){
      sqlite3_mutex_leave(db->mutex);
      return rc;
    }

    pTab = sqlite3LocateTable(&sParse, zTable, zDb);
    if( !pTab ){
      if( sParse.zErrMsg ){
        sqlite3_snprintf(sizeof(zErr), zErr, "%s", sParse.zErrMsg);
................................................................................
    }
    pBlob->flags = flags;
    pBlob->pCsr =  v->apCsr[0]->pCursor;
    sqlite3BtreeCacheOverflow(pBlob->pCsr);
    pBlob->pStmt = (sqlite3_stmt *)v;
    pBlob->iOffset = v->apCsr[0]->aOffset[iCol];
    pBlob->nByte = sqlite3VdbeSerialTypeLen(type);
    pBlob->db = db;
    *ppBlob = (sqlite3_blob *)pBlob;
    rc = SQLITE_OK;
  }else if( rc==SQLITE_OK ){
    sqlite3_snprintf(sizeof(zErr), zErr, "no such rowid: %lld", iRow);
    rc = SQLITE_ERROR;
  }

blob_open_out:
  zErr[sizeof(zErr)-1] = '\0';
  if( rc!=SQLITE_OK || db->mallocFailed ){
    sqlite3_finalize((sqlite3_stmt *)v);
  }
  sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr));
  rc = sqlite3ApiExit(db, rc);
  sqlite3_mutex_leave(db->mutex);
  return rc;
}

/*
** Close a blob handle that was previously created using
** sqlite3_blob_open().
*/
int sqlite3_blob_close(sqlite3_blob *pBlob){
  Incrblob *p = (Incrblob *)pBlob;
  sqlite3_stmt *pStmt;
  sqlite3_mutex *mutex = p->db->mutex;
  int rc;

  sqlite3_mutex_enter(mutex);
  rc = sqlite3_finalize(p->pStmt);
  sqlite3_mutex_leave(mutex);
  sqlite3_free(p);
  return rc;
}

/*
** Perform a read or write operation on a blob
*/
static int blobReadWrite(
  sqlite3_blob *pBlob, 
  void *z, 
  int n, 
  int iOffset, 
  int (*xCall)(BtCursor*, u32, u32, void*)
){
  int rc;
  Incrblob *p = (Incrblob *)pBlob;
  Vdbe *v;
  sqlite3 *db = p->db;  






  /* Request is out of range. Return a transient error. */
  if( (iOffset+n)>p->nByte ){
    return SQLITE_ERROR;
  }
  sqlite3_mutex_enter(db->mutex);

  /* If there is no statement handle, then the blob-handle has
  ** already been invalidated. Return SQLITE_ABORT in this case.
  */
  v = (Vdbe*)p->pStmt;
  if( v==0 ){
    rc = SQLITE_ABORT;
  }else{
    /* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is
    ** returned, clean-up the statement handle.
    */

    assert( db == v->db );
    rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
    if( rc==SQLITE_ABORT ){
      sqlite3VdbeFinalize(v);
      p->pStmt = 0;
    }else{
      db->errCode = rc;
      v->rc = rc;
    }
  }
  rc = sqlite3ApiExit(db, rc);
  sqlite3_mutex_leave(db->mutex);
  return rc;
}

/*
** Read data from a blob handle.
*/
int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
  return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData);
................................................................................
*/
int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
  return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData);
}

/*
** Query a blob handle for the size of the data.
**
** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
** so no mutex is required for access.
*/
int sqlite3_blob_bytes(sqlite3_blob *pBlob){
  Incrblob *p = (Incrblob *)pBlob;
  return p->nByte;
}

#endif /* #ifndef SQLITE_OMIT_INCRBLOB */