SQLite

Check-in [402a77c43d]
Login

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

Overview
Comment:Add some tests for sqlite3_load_extension(). (CVS 3239)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 402a77c43d4e4dcd2e1197cfaaa2ed51249a1b8f
User & Date: danielk1977 2006-06-14 10:38:03.000
Context
2006-06-14
10:47
Fix typo in test8.c. (CVS 3240) (check-in: 75be7d4988 user: danielk1977 tags: trunk)
10:38
Add some tests for sqlite3_load_extension(). (CVS 3239) (check-in: 402a77c43d user: danielk1977 tags: trunk)
08:48
Add tests for the new MATCH operator. (CVS 3238) (check-in: b4024c394d user: danielk1977 tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to Makefile.linux-gcc.
78
79
80
81
82
83
84






85
86
87
88
89
90
91

#### Tools used to build a static library.
#
AR = ar cr
#AR = /opt/mingw/bin/i386-mingw32-ar cr
RANLIB = ranlib
#RANLIB = /opt/mingw/bin/i386-mingw32-ranlib







#### Extra compiler options needed for programs that use the TCL library.
#
#TCL_FLAGS =
#TCL_FLAGS = -DSTATIC_BUILD=1
TCL_FLAGS = -I/home/drh/tcltk/8.4linux
#TCL_FLAGS = -I/home/drh/tcltk/8.4win -DSTATIC_BUILD=1







>
>
>
>
>
>







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

#### Tools used to build a static library.
#
AR = ar cr
#AR = /opt/mingw/bin/i386-mingw32-ar cr
RANLIB = ranlib
#RANLIB = /opt/mingw/bin/i386-mingw32-ranlib

MKSHLIB = gcc -shared
SO = so
SHPREFIX = lib
# SO = dll
# SHPREFIX =

#### Extra compiler options needed for programs that use the TCL library.
#
#TCL_FLAGS =
#TCL_FLAGS = -DSTATIC_BUILD=1
TCL_FLAGS = -I/home/drh/tcltk/8.4linux
#TCL_FLAGS = -I/home/drh/tcltk/8.4win -DSTATIC_BUILD=1
Changes to main.mk.
395
396
397
398
399
400
401







402
403
404
405
406
407
408
	  -e 's,",\\",g' \
	  -e 's,^,",' \
	  -e 's,$$,\\n",' \
	  $(TOP)/tool/spaceanal.tcl >spaceanal_tcl.h
	$(TCCX) $(TCL_FLAGS) -DTCLSH=2 -DSQLITE_TEST=1 -DSQLITE_DEBUG=1 -o \
 		sqlite3_analyzer$(EXE) $(TESTSRC) $(TOP)/src/tclsqlite.c \
		libsqlite3.a $(LIBTCL) $(THREADLIB)








# Rules used to build documentation
#
arch.html:	$(TOP)/www/arch.tcl
	tclsh $(TOP)/www/arch.tcl >arch.html

autoinc.html:	$(TOP)/www/autoinc.tcl







>
>
>
>
>
>
>







395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
	  -e 's,",\\",g' \
	  -e 's,^,",' \
	  -e 's,$$,\\n",' \
	  $(TOP)/tool/spaceanal.tcl >spaceanal_tcl.h
	$(TCCX) $(TCL_FLAGS) -DTCLSH=2 -DSQLITE_TEST=1 -DSQLITE_DEBUG=1 -o \
 		sqlite3_analyzer$(EXE) $(TESTSRC) $(TOP)/src/tclsqlite.c \
		libsqlite3.a $(LIBTCL) $(THREADLIB)

TEST_EXTENSION = $(SHPREFIX)testloadext.$(SO)
$(TEST_EXTENSION): $(TOP)/src/test_loadext.c
	$(MKSHLIB) $(TOP)/src/test_loadext.c -o $(TEST_EXTENSION)

extensiontest: testfixture$(EXE) $(TEST_EXTENSION)
	./testfixture$(EXE) $(TOP)/test/loadext.test

# Rules used to build documentation
#
arch.html:	$(TOP)/www/arch.tcl
	tclsh $(TOP)/www/arch.tcl >arch.html

autoinc.html:	$(TOP)/www/autoinc.tcl
Changes to src/loadext.c.
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
){
#ifdef SQLITE_LIBRARY_TYPE
  SQLITE_LIBRARY_TYPE handle;
  int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
  char *zErrmsg = 0;
  SQLITE_LIBRARY_TYPE *aHandle;

  db->nExtension++;
  aHandle = sqliteMalloc(sizeof(handle)*db->nExtension);
  if( aHandle==0 ){
    return SQLITE_NOMEM;
  }
  if( db->nExtension>0 ){
    memcpy(aHandle, db->aExtension, sizeof(handle)*(db->nExtension-1));
  }
  sqliteFree(db->aExtension);
  db->aExtension = aHandle;
  if( zProc==0 ){
    int i, j, n;
    char *z;
    char zBuf[200];
    n = strlen(zFile);
    for(i=n-1; i>0 && zFile[i-1]!='/'; i--){}
    for(j=i; zFile[j] && zFile[j]!='.'; j++){}







<
<
<
<
<
<
<
<
<
<







229
230
231
232
233
234
235










236
237
238
239
240
241
242
){
#ifdef SQLITE_LIBRARY_TYPE
  SQLITE_LIBRARY_TYPE handle;
  int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
  char *zErrmsg = 0;
  SQLITE_LIBRARY_TYPE *aHandle;











  if( zProc==0 ){
    int i, j, n;
    char *z;
    char zBuf[200];
    n = strlen(zFile);
    for(i=n-1; i>0 && zFile[i-1]!='/'; i--){}
    for(j=i; zFile[j] && zFile[j]!='.'; j++){}
290
291
292
293
294
295
296













297
298
299
300
301
302
303
    if( pzErrMsg ){
      *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
    }
    sqlite3_free(zErrmsg);
    SQLITE_CLOSE_LIBRARY(handle);
    return SQLITE_ERROR;
  }













  ((SQLITE_LIBRARY_TYPE*)db->aExtension)[db->nExtension-1] = handle;
  return SQLITE_OK;
#else
  if( pzErrMsg ){
    *pzErrMsg = sqlite3_mprintf("extension loading is disabled");
  }
  return SQLITE_ERROR;







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







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
    if( pzErrMsg ){
      *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
    }
    sqlite3_free(zErrmsg);
    SQLITE_CLOSE_LIBRARY(handle);
    return SQLITE_ERROR;
  }

  /* Append the new shared library handle to the db->aExtension array. */
  db->nExtension++;
  aHandle = sqliteMalloc(sizeof(handle)*db->nExtension);
  if( aHandle==0 ){
    return SQLITE_NOMEM;
  }
  if( db->nExtension>0 ){
    memcpy(aHandle, db->aExtension, sizeof(handle)*(db->nExtension-1));
  }
  sqliteFree(db->aExtension);
  db->aExtension = aHandle;

  ((SQLITE_LIBRARY_TYPE*)db->aExtension)[db->nExtension-1] = handle;
  return SQLITE_OK;
#else
  if( pzErrMsg ){
    *pzErrMsg = sqlite3_mprintf("extension loading is disabled");
  }
  return SQLITE_ERROR;
Changes to src/test1.c.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.210 2006/06/11 23:41:56 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>








|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.211 2006/06/14 10:38:03 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

1089
1090
1091
1092
1093
1094
1095



















































1096
1097
1098
1099
1100
1101
1102
  Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(primarykey));
  Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(autoincrement));
  Tcl_SetObjResult(interp, pRet);

  return TCL_OK;
}
#endif




















































/*
** Usage:  sqlite_abort
**
** Shutdown the process immediately.  This is not a clean shutdown.
** This command is used to test the recoverability of a database in
** the event of a program crash.







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







1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
  Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(primarykey));
  Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(autoincrement));
  Tcl_SetObjResult(interp, pRet);

  return TCL_OK;
}
#endif

/*
** Usage: sqlite3_load_extension DB-HANDLE FILE ?PROC?
*/
static int test_load_extension(
  ClientData clientData, /* Not used */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  Tcl_CmdInfo cmdInfo;
  sqlite3 *db;
  int rc;
  char *zDb;
  char *zFile;
  char *zProc = 0;
  char *zErr = 0;

  if( objc!=4 && objc!=3 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE FILE ?PROC?");
    return TCL_ERROR;
  }
  zDb = Tcl_GetString(objv[1]);
  zFile = Tcl_GetString(objv[2]);
  if( objc==4 ){
    zProc = Tcl_GetString(objv[3]);
  }

  /* Extract the C database handle from the Tcl command name */
  if( !Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
    Tcl_AppendResult(interp, "command not found: ", zDb, (char*)0);
    return TCL_ERROR;
  }
  db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
  assert(db);

  /* Call the underlying C function. If an error occurs, set rc to 
  ** TCL_ERROR and load any error string into the interpreter. If no 
  ** error occurs, set rc to TCL_OK.
  */
  rc = sqlite3_load_extension(db, zFile, zProc, &zErr);
  if( rc!=SQLITE_OK ){
    Tcl_SetResult(interp, zErr ? zErr : "", TCL_VOLATILE);
    rc = TCL_ERROR;
  }else{
    rc = TCL_OK;
  }
  sqlite3_free(zErr);

  return rc;
}

/*
** Usage:  sqlite_abort
**
** Shutdown the process immediately.  This is not a clean shutdown.
** This command is used to test the recoverability of a database in
** the event of a program crash.
3691
3692
3693
3694
3695
3696
3697



3698
3699
3700
3701
3702
3703
3704
#ifndef SQLITE_OMIT_SHARED_CACHE
     { "sqlite3_enable_shared_cache", test_enable_shared, 0  },
#endif
     { "sqlite3_libversion_number", test_libversion_number, 0  },
#ifdef SQLITE_ENABLE_COLUMN_METADATA
     { "sqlite3_table_column_metadata", test_table_column_metadata, 0  },
#endif



  };
  static int bitmask_size = sizeof(Bitmask)*8;
  int i;
  extern int sqlite3_os_trace;
  extern int sqlite3_where_trace;
  extern int sqlite3_sync_count, sqlite3_fullsync_count;
  extern int sqlite3_opentemp_count;







>
>
>







3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
#ifndef SQLITE_OMIT_SHARED_CACHE
     { "sqlite3_enable_shared_cache", test_enable_shared, 0  },
#endif
     { "sqlite3_libversion_number", test_libversion_number, 0  },
#ifdef SQLITE_ENABLE_COLUMN_METADATA
     { "sqlite3_table_column_metadata", test_table_column_metadata, 0  },
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
     { "sqlite3_load_extension", test_load_extension, 0  },
#endif
  };
  static int bitmask_size = sizeof(Bitmask)*8;
  int i;
  extern int sqlite3_os_trace;
  extern int sqlite3_where_trace;
  extern int sqlite3_sync_count, sqlite3_fullsync_count;
  extern int sqlite3_opentemp_count;
Added src/test_loadext.c.


















































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*
** 2006 June 14
**
** 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.
**
*************************************************************************
** Test extension for testing the sqlite3_load_extension() function.
**
** $Id: test_loadext.c,v 1.1 2006/06/14 10:38:03 danielk1977 Exp $
*/

#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1

/*
** The half() SQL function returns half of its input value.
*/
static void halfFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  sqlite3_result_double(context, 0.5*sqlite3_value_double(argv[0]));
}

/*
** Extension load function.
*/
int testloadext_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  SQLITE_EXTENSION_INIT2(pApi);
  sqlite3_create_function(db, "half", 1, SQLITE_ANY, 0, halfFunc, 0, 0);
  return 0;
}

/*
** Another extension entry point. This one always fails.
*/
int testbrokenext_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  char *zErr;
  SQLITE_EXTENSION_INIT2(pApi);
  zErr = sqlite3_mprintf("broken!");
  *pzErrMsg = zErr;
  return 1;
}
Added test/loadext.test.


















































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
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
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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
109
110
111
112
113
114
115
116
117
118
119
120
121
# 2006 July 14
#
# 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is in-memory database backend.
#
# $Id: loadext.test,v 1.1 2006/06/14 10:38:03 danielk1977 Exp $

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

if {$::tcl_platform(platform) eq "windows"} {
  set testextension testloadext.dll
} else {
  set testextension libtestloadext.so
}

if {![file exists $testextension]} {
  puts "Skipping loadext tests: Test extension not built..."
  finish_test
  return
}

# Test that loading the extension produces the expected results - adding
# the half() function to the specified database handle.
#
do_test loadext-1.1 {
  catchsql {
    SELECT half(1.0);
  }
} {1 {no such function: half}}
do_test loadext-1.2 {
  sqlite3_load_extension db $testextension
  catchsql {
    SELECT half(1.0);
  }
} {0 0.5}

# Test that a second database connection (db2) can load the extension also.
#
do_test loadext-1.3 {
  sqlite3 db2 test.db
  catchsql {
    SELECT half(1.0);
  } db2
} {1 {no such function: half}}
do_test loadext-1.4 {
  sqlite3_load_extension db2 $testextension
  catchsql {
    SELECT half(1.0);
  } db2
} {0 0.5}

# Close the first database connection. Then check that the second database
# can still use the half() function without a problem.
#
do_test loadext-1.5 {
  db close
  catchsql {
    SELECT half(1.0);
  } db2
} {0 0.5}

db2 close
sqlite3 db test.db

# Try to load an extension for which the file does not exist.
#
do_test loadext-2.1 {
  set rc [catch {
    sqlite3_load_extension db "xx${testextension}"
  } msg]
  list $rc $msg
} [list 1 [subst -nocommands \
  {unable to open shared library [xx${testextension}]}
]]

# Try to load an extension for which the file is not a shared object
#
do_test loadext-2.2 {
  set fd [open "xx${testextension}" w]
  puts $fd blah
  close $fd
  set rc [catch {
    sqlite3_load_extension db "xx${testextension}"
  } msg]
  list $rc $msg
} [list 1 [subst -nocommands \
  {unable to open shared library [xx${testextension}]}
]]

# Try to load an extension for which the file is present but the
# entry point is not.
#
do_test loadext-2.3 {
  set rc [catch {
    sqlite3_load_extension db $testextension icecream
  } msg]
  list $rc $msg
} [list 1 [subst -nocommands \
  {no entry point [icecream] in shared library [$testextension]}
]]

# Try to load an extension for which the entry point fails (returns non-zero) 
#
do_test loadext-2.4 {
  set rc [catch {
    sqlite3_load_extension db $testextension testbrokenext_init
  } msg]
  list $rc $msg
} {1 {error during initialization: broken!}}

finish_test

Changes to test/quick.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#
#    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 runs all tests.
#
# $Id: quick.test,v 1.43 2006/02/14 10:48:40 danielk1977 Exp $

proc lshift {lvar} {
  upvar $lvar l
  set ret [lindex $l 0]
  set l [lrange $l 1 end]
  return $ret
}








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#
#    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 runs all tests.
#
# $Id: quick.test,v 1.44 2006/06/14 10:38:03 danielk1977 Exp $

proc lshift {lvar} {
  upvar $lvar l
  set ret [lindex $l 0]
  set l [lrange $l 1 end]
  return $ret
}
39
40
41
42
43
44
45

46
47
48
49
50
51
52
  btree2.test
  btree3.test
  btree4.test
  btree5.test
  btree6.test
  corrupt.test
  crash.test

  malloc.test
  malloc2.test
  malloc3.test
  memleak.test
  misuse.test
  quick.test








>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  btree2.test
  btree3.test
  btree4.test
  btree5.test
  btree6.test
  corrupt.test
  crash.test
  loadext.test
  malloc.test
  malloc2.test
  malloc3.test
  memleak.test
  misuse.test
  quick.test