SQLite

Check-in [c7b4c28fbc]
Login

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

Overview
Comment:Add the "onecolumn" method to the TCL language bindings. (CVS 1076)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c7b4c28fbc0bca5645af5750fd353f4eca400b40
User & Date: drh 2003-08-19 14:31:01.000
Context
2003-08-20
01:03
Add the experimental "quote()" function to the set of build-in functions. (CVS 1077) (check-in: 9699c68508 user: drh tags: trunk)
2003-08-19
14:31
Add the "onecolumn" method to the TCL language bindings. (CVS 1076) (check-in: c7b4c28fbc user: drh tags: trunk)
2003-08-16
13:10
Make the compile work under cygwin. Tickets #327, #213, #316, #322, #349, #373, and #429. (CVS 1075) (check-in: 7d8d3252df user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to VERSION.
1
2.8.5
|
1
2.8.6
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.49 2003/06/06 19:00:42 drh Exp $
*/
#ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */

#include "sqliteInt.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.50 2003/08/19 14:31:02 drh Exp $
*/
#ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */

#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
243
244
245
246
247
248
249





























250
251
252
253
254
255
256
    }else{
      pElem = Tcl_NewObj();
    }
    Tcl_ListObjAppendElement(0, pList, pElem);
  }
  return 0;
}






























/*
** Called when the command is deleted.
*/
static void DbDeleteCmd(void *db){
  SqliteDb *pDb = (SqliteDb*)db;
  sqlite_close(pDb->db);







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







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
    }else{
      pElem = Tcl_NewObj();
    }
    Tcl_ListObjAppendElement(0, pList, pElem);
  }
  return 0;
}

/*
** This is a second alternative callback for database queries.  A the
** first column of the first row of the result is made the TCL result.
*/
static int DbEvalCallback3(
  void *clientData,      /* An instance of CallbackData */
  int nCol,              /* Number of columns in the result */
  char ** azCol,         /* Data for each column */
  char ** azN            /* Name for each column */
){
  Tcl_Interp *interp = (Tcl_Interp*)clientData;
  Tcl_Obj *pElem;
  if( azCol==0 ) return 1;
  if( nCol==0 ) return 1;
#ifdef UTF_TRANSLATION_NEEDED
  {
    Tcl_DString dCol;
    Tcl_DStringInit(&dCol);
    Tcl_ExternalToUtfDString(NULL, azCol[0], -1, &dCol);
    pElem = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
    Tcl_DStringFree(&dCol);
  }
#else
  pElem = Tcl_NewStringObj(azCol[0], -1);
#endif
  Tcl_SetObjResult(interp, pElem);
  return 1;
}

/*
** Called when the command is deleted.
*/
static void DbDeleteCmd(void *db){
  SqliteDb *pDb = (SqliteDb*)db;
  sqlite_close(pDb->db);
423
424
425
426
427
428
429
430

431
432
433
434
435
436
437
438
439
440
441
442
443
static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
  SqliteDb *pDb = (SqliteDb*)cd;
  int choice;
  static const char *DB_strs[] = {
    "authorizer",         "busy",              "changes",
    "close",              "complete",          "errorcode",
    "eval",               "function",          "last_insert_rowid",
    "timeout",            "trace",             0

  };
  enum DB_enum {
    DB_AUTHORIZER,        DB_BUSY,             DB_CHANGES,
    DB_CLOSE,             DB_COMPLETE,         DB_ERRORCODE,
    DB_EVAL,              DB_FUNCTION,         DB_LAST_INSERT_ROWID,
    DB_TIMEOUT,           DB_TRACE,            
  };

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







|
>





|







452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
  SqliteDb *pDb = (SqliteDb*)cd;
  int choice;
  static const char *DB_strs[] = {
    "authorizer",         "busy",              "changes",
    "close",              "complete",          "errorcode",
    "eval",               "function",          "last_insert_rowid",
    "onecolumn",          "timeout",            "trace",
    0
  };
  enum DB_enum {
    DB_AUTHORIZER,        DB_BUSY,             DB_CHANGES,
    DB_CLOSE,             DB_COMPLETE,         DB_ERRORCODE,
    DB_EVAL,              DB_FUNCTION,         DB_LAST_INSERT_ROWID,
    DB_ONECOLUMN,         DB_TIMEOUT,          DB_TRACE,            
  };

  if( objc<2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
    return TCL_ERROR;
  }
  if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){
710
711
712
713
714
715
716




























717
718
719
720
721
722
723
      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: {







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







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
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
      return TCL_ERROR;
    }
    rowid = sqlite_last_insert_rowid(pDb->db);
    pResult = Tcl_GetObjResult(interp);
    Tcl_SetIntObj(pResult, rowid);
    break;
  }

  /*
  **     $db onecolumn SQL
  **
  ** Return a single column from a single row of the given SQL query.
  */
  case DB_ONECOLUMN: {
    int rc;
    char *zSql;
    char *zErrMsg = 0;
    if( objc!=3 ){
      Tcl_WrongNumArgs(interp, 2, objv, "SQL");
      return TCL_ERROR;
    }
    zSql = Tcl_GetStringFromObj(objv[2], 0);
    rc = sqlite_exec(pDb->db, zSql, DbEvalCallback3, interp, &zErrMsg);
    if( rc==SQLITE_ABORT ){
      /* Do nothing.  This is normal. */
    }else if( zErrMsg ){
      Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
      free(zErrMsg);
      rc = TCL_ERROR;
    }else if( rc!=SQLITE_OK ){
      Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
      rc = 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.13 2003/04/23 12:25:25 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 authorizer, busy, changes, close, complete, errorcode, eval, function, last_insert_rowid, timeout, or trace}}
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.14 2003/08/19 14:31:02 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 authorizer, busy, changes, close, complete, errorcode, eval, function, last_insert_rowid, onecolumn, timeout, or trace}}
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"
    }
86
87
88
89
90
91
92

93

















94
  do_test tcl-2.2 {
    execsql "INSERT INTO t\251x VALUES(1,2.3)"
    db eval "SELECT * FROM t\251x" result break
    set result(*)
  } "a b\306"
}




















finish_test







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

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  do_test tcl-2.2 {
    execsql "INSERT INTO t\251x VALUES(1,2.3)"
    db eval "SELECT * FROM t\251x" result break
    set result(*)
  } "a b\306"
}

# Test the onecolumn method
#
do_test tcl-3.1 {
  execsql {
    INSERT INTO t1 SELECT a*2, b*2 FROM t1;
    INSERT INTO t1 SELECT a*2+1, b*2+1 FROM t1;
    INSERT INTO t1 SELECT a*2+3, b*2+3 FROM t1;
  }
  db onecolumn {SELECT * FROM t1 ORDER BY a}
} {10}
do_test tcl-3.2 {
  db onecolumn {SELECT * FROM t1 WHERE a<0}
} {}
do_test tcl-3.3 {
  set rc [catch {db onecolumn} errmsg]
  lappend rc $errmsg
} {1 {wrong # args: should be "db onecolumn SQL"}}


finish_test
Changes to www/tclsqlite.tcl.
1
2
3
4
5
6
7
8
9
10
11
#
# Run this Tcl script to generate the tclsqlite.html file.
#
set rcsid {$Id: tclsqlite.tcl,v 1.7 2002/04/12 10:09:00 drh Exp $}

puts {<html>
<head>
  <title>The Tcl interface to the SQLite library</title>
</head>
<body bgcolor=white>
<h1 align=center>



|







1
2
3
4
5
6
7
8
9
10
11
#
# Run this Tcl script to generate the tclsqlite.html file.
#
set rcsid {$Id: tclsqlite.tcl,v 1.8 2003/08/19 14:31:02 drh Exp $}

puts {<html>
<head>
  <title>The Tcl interface to the SQLite library</title>
</head>
<body bgcolor=white>
<h1 align=center>
57
58
59
60
61
62
63

64
65
66
67
68
69
70
<ul>
<li> busy
<li> changes
<li> close
<li> complete
<li> eval
<li> last_insert_rowid

<li> timeout
</ul>
</p>

<p>We will explain all of these methods, though not in that order.
We will be begin with the "close" method.</p>








>







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<ul>
<li> busy
<li> changes
<li> close
<li> complete
<li> eval
<li> last_insert_rowid
<li> onecolumn
<li> timeout
</ul>
</p>

<p>We will explain all of these methods, though not in that order.
We will be begin with the "close" method.</p>

245
246
247
248
249
250
251











252
253
254
255
256
257
258
should return "1" if it wants SQLite to abandon the current operation.

<h2>The "last_insert_rowid" method</h2>

<p>The "last_insert_rowid" method returns an integer which is the ROWID
of the most recently inserted database row.</p>












<h2>The "changes" method</h2>

<p>The "changes" method returns an integer which is the number of rows
in the database that were inserted, deleted, and/or modified by the most
recent "eval" method.</p>

}







>
>
>
>
>
>
>
>
>
>
>







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
should return "1" if it wants SQLite to abandon the current operation.

<h2>The "last_insert_rowid" method</h2>

<p>The "last_insert_rowid" method returns an integer which is the ROWID
of the most recently inserted database row.</p>

<h2>The "onecolumn" method</h2>

<p>The "onecolumn" method works like "eval" in that it evaluates the
SQL query statement given as its argument.  The difference is that
"onecolumn" returns a single element which is the first column of the
first row of the query result.</p>

<p>This is a convenience method.  It saves the user from having to
do a "<tt>[lindex&nbsp;...&nbsp;0]</tt>" on the results of an "eval"
in order to extract a single column result.</p>

<h2>The "changes" method</h2>

<p>The "changes" method returns an integer which is the number of rows
in the database that were inserted, deleted, and/or modified by the most
recent "eval" method.</p>

}