/ Check-in [03636c94]
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:Permit sqlite_exec() to be called from within user-defined functions. (CVS 1166)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 03636c94a542b1f90a3acfbe65a9c2976872073f
User & Date: drh 2004-01-07 19:24:48
Context
2004-01-07
20:37
Rework the fix to ticket #461 so that we do not have to do redundant tests of WHERE clause terms looking for NULLs. See also check-in (1103). (CVS 1167) check-in: 5fd58178 user: drh tags: trunk
19:24
Permit sqlite_exec() to be called from within user-defined functions. (CVS 1166) check-in: 03636c94 user: drh tags: trunk
18:52
Defer the {quote: MoveTo} opcode in VDBE until the data is actually needed. Sometimes the data is never needed, resulting in a performance increase. On an indexed order search with a large OFFSET, queries times can be an order of magnitude faster. (CVS 1165) check-in: d3e96da2 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/test1.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
291
292
293
294
295
296
297
298
299
















































300
301
302



303
304
305
306
307


308



309
310
311
312
313
314
315
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the printf() interface to SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.31 2004/01/06 00:44:25 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

................................................................................
  for(i=0; i<argc; i++){
    if( argv[i] ){
      sqlite_set_result_string(context, argv[i], -1);
      break;
    }
  }
}

/*
















































** Implementation of the x_sqlite_exec() function.  This function takes
** a single argument and attempts to execute that argument as SQL code.
** This is illegal and should set the SQLITE_MISUSE flag on the database.



** 
** This routine simulates the effect of having two threads attempt to
** use the same database at the same time.
*/
static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){


  sqlite_exec((sqlite*)sqlite_user_data(context), argv[0], 0, 0, 0);



}

/*
** Usage:  sqlite_test_create_function DB
**
** Call the sqlite_create_function API on the given database in order
** to create a function named "x_coalesce".  This function does the same thing







|







 









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



>
>
>





>
>
|
>
>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the printf() interface to SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.32 2004/01/07 19:24:48 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

................................................................................
  for(i=0; i<argc; i++){
    if( argv[i] ){
      sqlite_set_result_string(context, argv[i], -1);
      break;
    }
  }
}

/*
** A structure into which to accumulate text.
*/
struct dstr {
  int nAlloc;  /* Space allocated */
  int nUsed;   /* Space used */
  char *z;     /* The space */
};

/*
** Append text to a dstr
*/
static void dstrAppend(struct dstr *p, const char *z, int divider){
  int n = strlen(z);
  if( p->nUsed + n + 2 > p->nAlloc ){
    char *zNew;
    p->nAlloc = p->nAlloc*2 + n + 200;
    zNew = sqliteRealloc(p->z, p->nAlloc);
    if( zNew==0 ){
      sqliteFree(p->z);
      memset(p, 0, sizeof(*p));
      return;
    }
    p->z = zNew;
  }
  if( divider && p->nUsed>0 ){
    p->z[p->nUsed++] = divider;
  }
  memcpy(&p->z[p->nUsed], z, n+1);
  p->nUsed += n;
}

/*
** Invoked for each callback from sqliteExecFunc
*/
static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
  struct dstr *p = (struct dstr*)pData;
  int i;
  for(i=0; i<argc; i++){
    if( argv[i]==0 ){
      dstrAppend(p, "NULL", ' ');
    }else{
      dstrAppend(p, argv[i], ' ');
    }
  }
  return 0;
}

/*
** Implementation of the x_sqlite_exec() function.  This function takes
** a single argument and attempts to execute that argument as SQL code.
** This is illegal and should set the SQLITE_MISUSE flag on the database.
**
** 2004-Jan-07:  We have changed this to make it legal to call sqlite_exec()
** from within a function call.  
** 
** This routine simulates the effect of having two threads attempt to
** use the same database at the same time.
*/
static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){
  struct dstr x;
  memset(&x, 0, sizeof(x));
  sqlite_exec((sqlite*)sqlite_user_data(context), argv[0], 
      execFuncCallback, &x, 0);
  sqlite_set_result_string(context, x.z, x.nUsed);
  sqliteFree(x.z);
}

/*
** Usage:  sqlite_test_create_function DB
**
** Call the sqlite_create_function API on the given database in order
** to create a function named "x_coalesce".  This function does the same thing

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
1117
1118
1119
1120
1121
1122
1123

1124

1125
1126
1127
1128
1129
1130
1131
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.247 2004/01/07 18:52:57 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
    }
  }
  ctx.pFunc = (FuncDef*)pOp->p3;
  ctx.s.flags = STK_Null;
  ctx.z = 0;
  ctx.isError = 0;
  ctx.isStep = 0;

  (*ctx.pFunc->xFunc)(&ctx, n, (const char**)&zStack[p->tos-n+1]);

  sqliteVdbePopStack(p, n);
  p->tos++;
  aStack[p->tos] = ctx.s;
  if( ctx.s.flags & STK_Dyn ){
    zStack[p->tos] = ctx.z;
  }else if( ctx.s.flags & STK_Str ){
    zStack[p->tos] = aStack[p->tos].z;







|







 







>

>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.248 2004/01/07 19:24:48 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
    }
  }
  ctx.pFunc = (FuncDef*)pOp->p3;
  ctx.s.flags = STK_Null;
  ctx.z = 0;
  ctx.isError = 0;
  ctx.isStep = 0;
  if( sqliteSafetyOff(db) ) goto abort_due_to_misuse;
  (*ctx.pFunc->xFunc)(&ctx, n, (const char**)&zStack[p->tos-n+1]);
  if( sqliteSafetyOn(db) ) goto abort_due_to_misuse;
  sqliteVdbePopStack(p, n);
  p->tos++;
  aStack[p->tos] = ctx.s;
  if( ctx.s.flags & STK_Dyn ){
    zStack[p->tos] = ctx.z;
  }else if( ctx.s.flags & STK_Str ){
    zStack[p->tos] = aStack[p->tos].z;

Changes to test/misuse.test.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
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
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for the SQLITE_MISUSE detection logic.
# This test file leaks memory and file descriptors.
#
# $Id: misuse.test,v 1.3 2002/05/21 11:38:12 drh Exp $

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

# Make sure the test logic works
#
do_test misuse-1.1 {
................................................................................
do_test misuse-1.3 {
  sqlite_create_function $::DB
  sqlite_exec_printf $::DB {SELECT x_coalesce(NULL,a) AS 'xyz' FROM t1} {}
} {0 {xyz 1}}

# Use the x_sqlite_exec() SQL function to simulate the effect of two
# threads trying to use the same database at the same time.




#
do_test misuse-1.4 {
  sqlite_exec_printf $::DB {
     SELECT x_sqlite_exec('SELECT * FROM t1');
  } {}
} {21 {library routine called out of sequence}}
do_test misuse-1.5 {
  sqlite_exec_printf $::DB {SELECT * FROM t1} {}
} {21 {library routine called out of sequence}}
do_test misuse-1.6 {
  catchsql {
    SELECT * FROM t1
  }
} {1 {library routine called out of sequence}}

# Attempt to register a new SQL function while an sqlite_exec() is active.
#
do_test misuse-2.1 {
  db close
  set ::DB [sqlite db test2.db]
  execsql {







|







 







>
>
>
>



|

|


|




|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
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
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for the SQLITE_MISUSE detection logic.
# This test file leaks memory and file descriptors.
#
# $Id: misuse.test,v 1.4 2004/01/07 19:24:48 drh Exp $

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

# Make sure the test logic works
#
do_test misuse-1.1 {
................................................................................
do_test misuse-1.3 {
  sqlite_create_function $::DB
  sqlite_exec_printf $::DB {SELECT x_coalesce(NULL,a) AS 'xyz' FROM t1} {}
} {0 {xyz 1}}

# Use the x_sqlite_exec() SQL function to simulate the effect of two
# threads trying to use the same database at the same time.
#
# It used to be prohibited to invoke sqlite_exec() from within a function,
# but that has changed.  The following tests used to cause errors but now
# they do not.
#
do_test misuse-1.4 {
  sqlite_exec_printf $::DB {
     SELECT x_sqlite_exec('SELECT * FROM t1') AS xyz;
  } {}
} {0 {xyz {1 2}}}
do_test misuse-1.5 {
  sqlite_exec_printf $::DB {SELECT * FROM t1} {}
} {0 {a b 1 2}}
do_test misuse-1.6 {
  catchsql {
    SELECT * FROM t1
  }
} {0 {1 2}}

# Attempt to register a new SQL function while an sqlite_exec() is active.
#
do_test misuse-2.1 {
  db close
  set ::DB [sqlite db test2.db]
  execsql {