/ Check-in [fd5b2f23]
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:Adding the sqlite3_stmt_readonly() interface.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: fd5b2f23dd5111d2f0934dd828bae36b755024c1
User & Date: drh 2010-11-16 23:10:26
Context
2010-11-17
02:02
Restrict the scope of the sqlite3_stmt_readonly() interface to a specific subset of prepared statement types. check-in: 919b06c3 user: drh tags: trunk
2010-11-16
23:10
Adding the sqlite3_stmt_readonly() interface. check-in: fd5b2f23 user: drh tags: trunk
02:49
Use the estimated number of rows computed for subqueries in the cost computations for outer queries. check-in: 56bbc539 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/sqlite.h.in.

2624
2625
2626
2627
2628
2629
2630















2631
2632
2633
2634
2635
2636
2637
**
** ^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
** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
*/
const char *sqlite3_sql(sqlite3_stmt *pStmt);
















/*
** CAPI3REF: Dynamically Typed Value Object
** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value}
**
** SQLite uses the sqlite3_value object to represent all values
** that can be stored in a database table. SQLite uses dynamic typing
** for the values it stores.  ^Values stored in sqlite3_value objects







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







2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
**
** ^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
** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
*/
const char *sqlite3_sql(sqlite3_stmt *pStmt);

/*
** CAPI3REF: Determine If An SQL Statement Writes The Database
**
** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if
** the [prepared statement] X is guaranteed to leave the database file
** unmodified.  ^If the sqlite3_stmt_readonly(X) interface returns false (zero)
** then evaluating the statement might change the database file, but this
** is not guaranteed as the write operation might be conditional and the
** condition might not be met.  ^If X is a NULL pointer then
** sqlite3_stmt_readonly(X) returns true.  If X is a non-NULL pointer but
** is not a pointer to a valid, unfinalized prepared statement, then the
** behavior is undefined and probably harmful.
*/
int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);

/*
** CAPI3REF: Dynamically Typed Value Object
** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value}
**
** SQLite uses the sqlite3_value object to represent all values
** that can be stored in a database table. SQLite uses dynamic typing
** for the values it stores.  ^Values stored in sqlite3_value objects

Changes to src/test1.c.

2295
2296
2297
2298
2299
2300
2301



























2302
2303
2304
2305
2306
2307
2308
....
5388
5389
5390
5391
5392
5393
5394

5395
5396
5397
5398
5399
5400
5401
  if( pStmt ){
    if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
    Tcl_AppendResult(interp, zBuf, 0);
  }
  return TCL_OK;
}





























/*
** Usage:  sqlite3_reset  STMT 
**
** Reset a statement handle.
*/
static int test_reset(
................................................................................
     { "sqlite3_reset",                 test_reset         ,0 },
     { "sqlite3_expired",               test_expired       ,0 },
     { "sqlite3_transfer_bindings",     test_transfer_bind ,0 },
     { "sqlite3_changes",               test_changes       ,0 },
     { "sqlite3_step",                  test_step          ,0 },
     { "sqlite3_sql",                   test_sql           ,0 },
     { "sqlite3_next_stmt",             test_next_stmt     ,0 },


     { "sqlite3_release_memory",        test_release_memory,     0},
     { "sqlite3_soft_heap_limit",       test_soft_heap_limit,    0},
     { "sqlite3_thread_cleanup",        test_thread_cleanup,     0},
     { "sqlite3_pager_refcounts",       test_pager_refcounts,    0},

     { "sqlite3_load_extension",        test_load_extension,     0},







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







 







>







2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
....
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
  if( pStmt ){
    if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
    Tcl_AppendResult(interp, zBuf, 0);
  }
  return TCL_OK;
}

/*
** Usage:  sqlite3_stmt_readonly  STMT
**
** Return true if STMT is a NULL pointer or a pointer to a statement
** that is guaranteed to leave the database unmodified.
*/
static int test_stmt_readonly(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_stmt *pStmt;
  int rc;

  if( objc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
        Tcl_GetStringFromObj(objv[0], 0), " STMT", 0);
    return TCL_ERROR;
  }

  if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  rc = sqlite3_stmt_readonly(pStmt);
  Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc));
  return TCL_OK;
}


/*
** Usage:  sqlite3_reset  STMT 
**
** Reset a statement handle.
*/
static int test_reset(
................................................................................
     { "sqlite3_reset",                 test_reset         ,0 },
     { "sqlite3_expired",               test_expired       ,0 },
     { "sqlite3_transfer_bindings",     test_transfer_bind ,0 },
     { "sqlite3_changes",               test_changes       ,0 },
     { "sqlite3_step",                  test_step          ,0 },
     { "sqlite3_sql",                   test_sql           ,0 },
     { "sqlite3_next_stmt",             test_next_stmt     ,0 },
     { "sqlite3_stmt_readonly",         test_stmt_readonly ,0 },

     { "sqlite3_release_memory",        test_release_memory,     0},
     { "sqlite3_soft_heap_limit",       test_soft_heap_limit,    0},
     { "sqlite3_thread_cleanup",        test_thread_cleanup,     0},
     { "sqlite3_pager_refcounts",       test_pager_refcounts,    0},

     { "sqlite3_load_extension",        test_load_extension,     0},

Changes to src/vdbeapi.c.

1261
1262
1263
1264
1265
1266
1267








1268
1269
1270
1271
1272
1273
1274
** in the argument belongs.  This is the same database handle that was
** the first argument to the sqlite3_prepare() that was used to create
** the statement in the first place.
*/
sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
  return pStmt ? ((Vdbe*)pStmt)->db : 0;
}









/*
** Return a pointer to the next prepared statement after pStmt associated
** with database connection pDb.  If pStmt is NULL, return the first
** prepared statement for the database connection.  Return NULL if there
** are no more.
*/







>
>
>
>
>
>
>
>







1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
** in the argument belongs.  This is the same database handle that was
** the first argument to the sqlite3_prepare() that was used to create
** the statement in the first place.
*/
sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
  return pStmt ? ((Vdbe*)pStmt)->db : 0;
}

/*
** Return true if the prepared statement is guaranteed to not modify the
** database.
*/
int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
  return pStmt ? ((Vdbe*)pStmt)->readOnly : 1;
}

/*
** Return a pointer to the next prepared statement after pStmt associated
** with database connection pDb.  If pStmt is NULL, return the first
** prepared statement for the database connection.  Return NULL if there
** are no more.
*/

Changes to test/capi3d.test.

6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
..
84
85
86
87
88
89
90
91

92





















93
#    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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  
#
# This file is devoted to testing the sqlite3_next_stmt interface.

#
# $Id: capi3d.test,v 1.2 2008/07/14 15:11:20 drh Exp $
#

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

................................................................................
  do_test capi3-1.2.$i.2 {
    foreach p [scramble $::stmtlist] {
      sqlite3_finalize $p
    }
    sqlite3_next_stmt db 0
  } {}
}
      























finish_test







|
>







 







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

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
85
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
113
114
115
116
#    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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  
#
# This file is devoted to testing the sqlite3_next_stmt and
# sqlite3_stmt_readonly interfaces.
#
# $Id: capi3d.test,v 1.2 2008/07/14 15:11:20 drh Exp $
#

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

................................................................................
  do_test capi3-1.2.$i.2 {
    foreach p [scramble $::stmtlist] {
      sqlite3_finalize $p
    }
    sqlite3_next_stmt db 0
  } {}
}

# Tests for the is-read-only interface.
#
proc test_is_readonly {testname sql truth} {
  do_test $testname [format {
    set DB [sqlite3_connection_pointer db]
    set STMT [sqlite3_prepare $DB {%s} -1 TAIL]
    set rc [sqlite3_stmt_readonly $STMT]
    sqlite3_finalize $STMT
    set rc
  } $sql] $truth
}

test_is_readonly capi3d-2.1 {SELECT * FROM sqlite_master} 1
test_is_readonly capi3d-2.2 {CREATE TABLE t1(x)} 0
db eval {CREATE TABLE t1(x)}
test_is_readonly capi3d-2.3 {INSERT INTO t1 VALUES(5)} 0
test_is_readonly capi3d-2.4 {UPDATE t1 SET x=x+1 WHERE x<0} 0
test_is_readonly capi3d-2.5 {SELECT * FROM t1} 1
do_test capi3-2.99 {
  sqlite3_stmt_readonly 0
} 1


finish_test