SQLite

Check-in [332164d645]
Login

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

Overview
Comment:Add the sqlite_open_aux_file() API. (CVS 646)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 332164d6455658ca633a1dc49811d9fb0fd4b01c
User & Date: drh 2002-06-25 19:31:18.000
Context
2002-06-26
02:45
The datatype of the i-th column in the result set is given by the azColName(argc+1+i) parameter to the callback. (CVS 647) (check-in: bdb006b809 user: drh tags: trunk)
2002-06-25
19:31
Add the sqlite_open_aux_file() API. (CVS 646) (check-in: 332164d645 user: drh tags: trunk)
15:19
Version 2.5.3 (CVS 645) (check-in: d5cb675432 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/main.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** 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.84 2002/06/25 01:09:11 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** This is the callback routine for the code that initializes the







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** 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.85 2002/06/25 19:31:18 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>

/*
** This is the callback routine for the code that initializes the
706
707
708
709
710
711
712
713


714
715
716
717
718
719
720
721
722








































  p->xStep = xStep;
  p->xFinalize = xFinalize;
  p->pUserData = pUserData;
  return 0;
}

/*
** Change the datatype for all functions with a given name.


*/
int sqlite_function_type(sqlite *db, const char *zName, int dataType){
  FuncDef *p = (FuncDef*)sqliteHashFind(&db->aFunc, zName, strlen(zName));
  while( p ){
    p->dataType = dataType; 
    p = p->pNext;
  }
  return SQLITE_OK;
}















































|
>
>









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
759
760
761
762
763
764
  p->xStep = xStep;
  p->xFinalize = xFinalize;
  p->pUserData = pUserData;
  return 0;
}

/*
** Change the datatype for all functions with a given name.  See the
** header comment for the prototype of this function in sqlite.h for
** additional information.
*/
int sqlite_function_type(sqlite *db, const char *zName, int dataType){
  FuncDef *p = (FuncDef*)sqliteHashFind(&db->aFunc, zName, strlen(zName));
  while( p ){
    p->dataType = dataType; 
    p = p->pNext;
  }
  return SQLITE_OK;
}

/*
** Attempt to open the file named in the argument as the auxiliary database
** file.  The auxiliary database file is used to store TEMP tables.  But
** by using this API, it is possible to trick SQLite into opening two
** separate databases and acting on them as if they were one.
**
** This routine closes the existing auxiliary database file, which will
** cause any previously created TEMP tables to be created.
**
** The zName parameter can be a NULL pointer or an empty string to cause
** a temporary file to be opened and automatically deleted when closed.
*/
int sqlite_open_aux_file(sqlite *db, const char *zName, char **pzErrMsg){
  int rc;
  if( zName && zName[0]==0 ) zName = 0;
  if( sqliteSafetyOn(db) ) goto openaux_misuse;
  sqliteResetInternalSchema(db);
  if( db->pBeTemp!=0 ){
    sqliteBtreeClose(db->pBeTemp);
  }
  rc = sqliteBtreeOpen(zName, 0, MAX_PAGES, &db->pBeTemp);
  if( rc ){
    if( zName==0 ) zName = "a temporary file";
    sqliteSetString(pzErrMsg, "unable to open ", zName, 
      ": ", sqlite_error_string(rc), 0);
    sqliteStrRealloc(pzErrMsg);
    sqliteSafetyOff(db);
    return rc;
  }
  rc = sqliteInit(db, pzErrMsg);
  if( sqliteSafetyOff(db) ) goto openaux_misuse;
  sqliteStrRealloc(pzErrMsg);
  return rc;

openaux_misuse:
  sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), 0);
  sqliteStrRealloc(pzErrMsg);
  return SQLITE_MISUSE;
}
Changes to src/shell.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
** $Id: shell.c,v 1.58 2002/06/25 01:09:12 drh Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "sqlite.h"
#include <ctype.h>








|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
** $Id: shell.c,v 1.59 2002/06/25 19:31:18 drh Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "sqlite.h"
#include <ctype.h>

482
483
484
485
486
487
488

489
490
491
492
493
494
495
  ".header(s) ON|OFF      Turn display of headers on or off\n"
  ".help                  Show this message\n"
  ".indices TABLE         Show names of all indices on TABLE\n"
  ".mode MODE             Set mode to one of \"line(s)\", \"column(s)\", \n"
  "                       \"insert\", \"list\", or \"html\"\n"
  ".mode insert TABLE     Generate SQL insert statements for TABLE\n"
  ".nullvalue STRING      Print STRING instead of nothing for NULL data\n"

  ".output FILENAME       Send output to FILENAME\n"
  ".output stdout         Send output to the screen\n"
  ".prompt MAIN CONTINUE  Replace the standard prompts\n"
  ".quit                  Exit this program\n"
  ".read FILENAME         Execute SQL in FILENAME\n"
  ".reindex ?TABLE?       Rebuild indices\n"
/*  ".rename OLD NEW        Change the name of a table or index\n" */







>







482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
  ".header(s) ON|OFF      Turn display of headers on or off\n"
  ".help                  Show this message\n"
  ".indices TABLE         Show names of all indices on TABLE\n"
  ".mode MODE             Set mode to one of \"line(s)\", \"column(s)\", \n"
  "                       \"insert\", \"list\", or \"html\"\n"
  ".mode insert TABLE     Generate SQL insert statements for TABLE\n"
  ".nullvalue STRING      Print STRING instead of nothing for NULL data\n"
  ".openaux FILENAME      Use FILENAME to hold TEMP tables\n"
  ".output FILENAME       Send output to FILENAME\n"
  ".output stdout         Send output to the screen\n"
  ".prompt MAIN CONTINUE  Replace the standard prompts\n"
  ".quit                  Exit this program\n"
  ".read FILENAME         Execute SQL in FILENAME\n"
  ".reindex ?TABLE?       Rebuild indices\n"
/*  ".rename OLD NEW        Change the name of a table or index\n" */
697
698
699
700
701
702
703









704
705
706
707
708
709
710
      fprintf(stderr,"mode should be on of: column html insert line list\n");
    }
  }else

  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
    sprintf(p->nullvalue, "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
  }else










  if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
    if( p->out!=stdout ){
      fclose(p->out);
    }
    if( strcmp(azArg[1],"stdout")==0 ){
      p->out = stdout;







>
>
>
>
>
>
>
>
>







698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
      fprintf(stderr,"mode should be on of: column html insert line list\n");
    }
  }else

  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
    sprintf(p->nullvalue, "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
  }else

  if( c=='o' && strncmp(azArg[0], "openaux", n)==0 ){
    char *zErrMsg = 0;
    sqlite_open_aux_file(db, nArg>=2 ? azArg[1] : 0, &zErrMsg);
    if( zErrMsg ){
      fprintf(stderr,"Error: %s\n", zErrMsg);
      free(zErrMsg);
    }
  }else

  if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
    if( p->out!=stdout ){
      fclose(p->out);
    }
    if( strcmp(azArg[1],"stdout")==0 ){
      p->out = stdout;
Changes to src/sqlite.h.in.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.32 2002/06/20 11:36:50 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** The version of the SQLite library.







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.33 2002/06/25 19:31:18 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** The version of the SQLite library.
492
493
494
495
496
497
498








499
500
501
502
503
/*
** The next routine returns the number of calls to xStep for a particular
** aggregate function instance.  The current call to xStep counts so this
** routine always returns at least 1.
*/
int sqlite_aggregate_count(sqlite_func*);









#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif

#endif /* _SQLITE_H_ */







>
>
>
>
>
>
>
>





492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
/*
** The next routine returns the number of calls to xStep for a particular
** aggregate function instance.  The current call to xStep counts so this
** routine always returns at least 1.
*/
int sqlite_aggregate_count(sqlite_func*);

/*
** Attempt to open the file named in the argument as the auxiliary database
** file.  The auxiliary database file is used to store TEMP tables.  But
** by using this API, it is possible to trick SQLite into opening two
** separate databases and acting on them as if they were one.
*/
int sqlite_open_aux_file(sqlite *db, const char *zName, char **pzErrMsg);

#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif

#endif /* _SQLITE_H_ */
Changes to src/tclsqlite.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** A TCL Interface to SQLite
**
** $Id: tclsqlite.c,v 1.32 2002/05/10 13:14:07 drh Exp $
*/
#ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */

#include "sqlite.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** A TCL Interface to SQLite
**
** $Id: tclsqlite.c,v 1.33 2002/06/25 19:31:18 drh Exp $
*/
#ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */

#include "sqlite.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
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
** The first command opens a connection to the "my_database" database
** and calls that connection "db1".  The second command causes this
** subroutine to be invoked.
*/
static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
  SqliteDb *pDb = (SqliteDb*)cd;
  int choice;
  static char *DB_optStrs[] = {
     "busy",  "changes",            "close",    "complete", 
     "eval",  "last_insert_rowid",  "timeout",  0

  };
  enum DB_opts {
     DB_BUSY, DB_CHANGES,           DB_CLOSE,   DB_COMPLETE,
     DB_EVAL, DB_LAST_INSERT_ROWID, DB_TIMEOUT

  };

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
    return TCL_ERROR;
  }
  if( Tcl_GetIndexFromObj(interp, objv[1], DB_optStrs, "option", 0, &choice) ){
    return TCL_ERROR;
  }

  switch( (enum DB_opts)choice ){

  /*    $db busy ?CALLBACK?
  **
  ** Invoke the given callback if an SQL statement attempts to open
  ** a locked database file.
  */
  case DB_BUSY: {







|
|
|
>

|
|
|
>






|



|







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
** The first command opens a connection to the "my_database" database
** and calls that connection "db1".  The second command causes this
** subroutine to be invoked.
*/
static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
  SqliteDb *pDb = (SqliteDb*)cd;
  int choice;
  static char *DB_strs[] = {
    "busy",               "changes",           "close",
    "complete",           "eval",              "last_insert_rowid",
    "open_aux_file",      "timeout",           0
  };
  enum DB_enum {
    DB_BUSY,              DB_CHANGES,          DB_CLOSE,
    DB_COMPLETE,          DB_EVAL,             DB_LAST_INSERT_ROWID,
    DB_OPEN_AUX_FILE,     DB_TIMEOUT,          
  };

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
    return TCL_ERROR;
  }
  if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){
    return TCL_ERROR;
  }

  switch( (enum DB_enum)choice ){

  /*    $db busy ?CALLBACK?
  **
  ** Invoke the given callback if an SQL statement attempts to open
  ** a locked database file.
  */
  case DB_BUSY: {
458
459
460
461
462
463
464




























465
466
467
468
469
470
471
      return TCL_ERROR;
    }
    rowid = sqlite_last_insert_rowid(pDb->db);
    pResult = Tcl_GetObjResult(interp);
    Tcl_SetIntObj(pResult, rowid);
    break;
  }





























  /*
  **     $db timeout MILLESECONDS
  **
  ** Delay for the number of milliseconds specified when a file is locked.
  */
  case DB_TIMEOUT: {







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







460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
      return TCL_ERROR;
    }
    rowid = sqlite_last_insert_rowid(pDb->db);
    pResult = Tcl_GetObjResult(interp);
    Tcl_SetIntObj(pResult, rowid);
    break;
  }

  /*
  **     $db open_aux_file  FILENAME
  **
  ** Begin using FILENAME as the database file used to store temporary
  ** tables.
  */
  case DB_OPEN_AUX_FILE: {
    const char *zFilename;
    char *zErrMsg = 0;
    int rc;
    if( objc!=3 ){
      Tcl_WrongNumArgs(interp, 2, objv, "FILENAME");
      return TCL_ERROR;
    }
    zFilename = Tcl_GetStringFromObj(objv[2], 0);
    rc = sqlite_open_aux_file(pDb->db, zFilename, &zErrMsg);
    if( rc!=0 ){
      if( zErrMsg ){
        Tcl_AppendResult(interp, zErrMsg, 0);
        free(zErrMsg);
      }else{
        Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
      }
      return TCL_ERROR;
    }
    break;
  }

  /*
  **     $db timeout MILLESECONDS
  **
  ** Delay for the number of milliseconds specified when a file is locked.
  */
  case DB_TIMEOUT: {
Changes to test/tclsqlite.test.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# This file implements regression tests for TCL interface to the
# SQLite library. 
#
# Actually, all tests are based on the TCL interface, so the main
# interface is pretty well tested.  This file contains some addition
# tests for fringe issues that the main test suite does not cover.
#
# $Id: tclsqlite.test,v 1.6 2002/04/12 10:09:00 drh Exp $

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

# Check the error messages generated by tclsqlite
#
do_test tcl-1.1 {
  set v [catch {sqlite bogus} msg]
  lappend v $msg
} {1 {wrong # args: should be "sqlite HANDLE FILENAME ?MODE?"}}
do_test tcl-1.2 {
  set v [catch {db bogus} msg]
  lappend v $msg
} {1 {bad option "bogus": must be busy, changes, close, complete, eval, last_insert_rowid, or timeout}}
do_test tcl-1.3 {
  execsql {CREATE TABLE t1(a int, b int)}
  execsql {INSERT INTO t1 VALUES(10,20)}
  set v [catch {
    db eval {SELECT * FROM t1} data {
      error "The error message"
    }







|













|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# This file implements regression tests for TCL interface to the
# SQLite library. 
#
# Actually, all tests are based on the TCL interface, so the main
# interface is pretty well tested.  This file contains some addition
# tests for fringe issues that the main test suite does not cover.
#
# $Id: tclsqlite.test,v 1.7 2002/06/25 19:31:18 drh Exp $

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

# Check the error messages generated by tclsqlite
#
do_test tcl-1.1 {
  set v [catch {sqlite bogus} msg]
  lappend v $msg
} {1 {wrong # args: should be "sqlite HANDLE FILENAME ?MODE?"}}
do_test tcl-1.2 {
  set v [catch {db bogus} msg]
  lappend v $msg
} {1 {bad option "bogus": must be busy, changes, close, complete, eval, last_insert_rowid, open_aux_file, or timeout}}
do_test tcl-1.3 {
  execsql {CREATE TABLE t1(a int, b int)}
  execsql {INSERT INTO t1 VALUES(10,20)}
  set v [catch {
    db eval {SELECT * FROM t1} data {
      error "The error message"
    }