/ Check-in [059b1f61]
Login

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

Overview
Comment:The default entry point for loadable extensions is now always sqlite3_extension_init(). (CVS 3268)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 059b1f61406ca60fdbd3ec59c5b15fadc6552564
User & Date: drh 2006-06-17 13:21:32
Context
2006-06-17
14:12
Add the load_extension() SQL function. (CVS 3269) check-in: e08e2dda user: drh tags: trunk
13:21
The default entry point for loadable extensions is now always sqlite3_extension_init(). (CVS 3268) check-in: 059b1f61 user: drh tags: trunk
11:30
Add newly created virtual tables to the current transaction. (CVS 3267) check-in: ea7e4eca user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/loadext.c.

193
194
195
196
197
198
199
200
201

202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
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
# define SQLITE_OPEN_LIBRARY(A)  dlopen(A, RTLD_NOW | RTLD_GLOBAL)
# define SQLITE_FIND_SYMBOL(A,B) dlsym(A,B)
# define SQLITE_CLOSE_LIBRARY(A) dlclose(A)
#endif

/*
** Attempt to load an SQLite extension library contained in the file
** zFile.  The entry point is zProc.  zProc may be 0 in which case the
** name of the entry point is derived from the filename.

**
** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong.
**
** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with 
** error message text.  The calling function should free this memory
** by calling sqlite3_free().
**
** The entry point name is derived from the filename according to the
** following steps:
**
**    * Convert the name to lower case
**    * Remove the path prefix from the name
**    * Remove the first "." and all following characters from the name
**    * If the name begins with "lib" remove the first 3 characters
**    * Remove all characters that are not US-ASCII alphanumerics
**      or underscores
**    * Remove any leading digits and underscores from the name
**    * Append "_init" to the name
**
** So, for example, if the input filename is "/home/drh/libtest1.52.so"
** then the entry point would be computed as "test1_init".
**
** The derived entry point name is limited to a reasonable number of
** characters (currently 200).
*/
int sqlite3_load_extension(
  sqlite3 *db,          /* Load the extension into this database connection */
  const char *zFile,    /* Name of the shared library containing extension */
  const char *zProc,    /* Entry point.  Derived from zFile if 0 */
  char **pzErrMsg       /* Put error message here if not 0 */
){
#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++){}
    if( j-i > sizeof(zBuf)-10 ) j = i + sizeof(zBuf) - 10;
    memcpy(zBuf, &zFile[i], j - i);
    zBuf[j - i] = 0;
    z = zBuf;
    for(i=j=0; z[i]; i++){
      int c = z[i];
      if( (c & 0x80)!=0 || (!isalnum(c) && c!='_') ) continue;
      z[j++] = tolower(c);
    }
    z[j] = 0;
    if( strncmp(z, "lib", 3)==0 ){
      z += 3;
    }
    while( z[0] && !isalpha(z[0]) ){
      z++;
    }
    strcat(z, "_init");
    zProc = z;
  }

  handle = SQLITE_OPEN_LIBRARY(zFile);
  if( handle==0 ){
    if( pzErrMsg ){
      *pzErrMsg = sqlite3_mprintf("unable to open shared library [%s]", zFile);
    }







|
|
>






<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




|









<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|







193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208


















209
210
211
212
213
214
215
216
217
218
219
220
221
222























223
224
225
226
227
228
229
230
# define SQLITE_OPEN_LIBRARY(A)  dlopen(A, RTLD_NOW | RTLD_GLOBAL)
# define SQLITE_FIND_SYMBOL(A,B) dlsym(A,B)
# define SQLITE_CLOSE_LIBRARY(A) dlclose(A)
#endif

/*
** Attempt to load an SQLite extension library contained in the file
** zFile.  The entry point is zProc.  zProc may be 0 in which case a
** default entry point name (sqlite3_extension_init) is used.  Use
** of the default name is recommended.
**
** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong.
**
** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with 
** error message text.  The calling function should free this memory
** by calling sqlite3_free().


















*/
int sqlite3_load_extension(
  sqlite3 *db,          /* Load the extension into this database connection */
  const char *zFile,    /* Name of the shared library containing extension */
  const char *zProc,    /* Entry point.  Use "sqlite3_extension_init" if 0 */
  char **pzErrMsg       /* Put error message here if not 0 */
){
#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 ){























    zProc = "sqlite3_extension_init";
  }

  handle = SQLITE_OPEN_LIBRARY(zFile);
  if( handle==0 ){
    if( pzErrMsg ){
      *pzErrMsg = sqlite3_mprintf("unable to open shared library [%s]", zFile);
    }

Changes to src/test_schema.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the virtual table interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test_schema.c,v 1.3 2006/06/16 06:17:47 danielk1977 Exp $
*/

/* The code in this file defines a sqlite3 module that provides
** a read-only view of the current database schema. There is one
** row in the schema table for each column in the database.
*/
#define SCHEMA \
"CREATE TABLE x("                                                            \
  "database,"          /* Name of database (i.e. main, temp etc.) */         \
  "tablename,"         /* Name of table */                                   \
  "cid,"               /* Column number (from left-to-right, 0 upward) */    \
  "name,"              /* Column name */                                     \
................................................................................
}

#else

/*
** Extension load function.
*/
int schema_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  SQLITE_EXTENSION_INIT2(pApi);
  sqlite3_create_module(db, "schema", &schemaModule, 0);
  return 0;
}

#endif







|


|
|
|







 







|










9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the virtual table interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test_schema.c,v 1.4 2006/06/17 13:21:33 drh Exp $
*/

/* The code in this file defines a sqlite3 virtual-table module that
** provides a read-only view of the current database schema. There is one
** row in the schema table for each column in the database schema.
*/
#define SCHEMA \
"CREATE TABLE x("                                                            \
  "database,"          /* Name of database (i.e. main, temp etc.) */         \
  "tablename,"         /* Name of table */                                   \
  "cid,"               /* Column number (from left-to-right, 0 upward) */    \
  "name,"              /* Column name */                                     \
................................................................................
}

#else

/*
** Extension load function.
*/
int sqlite3_extension_init(
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  SQLITE_EXTENSION_INIT2(pApi);
  sqlite3_create_module(db, "schema", &schemaModule, 0);
  return 0;
}

#endif

Changes to test/loadext.test.

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
..
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
...
114
115
116
117
118
119
120
121
#    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.
................................................................................
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 {
................................................................................
  set rc [catch {
    sqlite3_load_extension db $testextension testbrokenext_init
  } msg]
  list $rc $msg
} {1 {error during initialization: broken!}}

finish_test








|




>
>

|

|


>
>
>
>

>
>
>
>
>
|
>
|
|
>











|







 







|







 







|



|





|



|



|







 







<
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
..
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
...
127
128
129
130
131
132
133

#    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.2 2006/06/17 13:21:33 drh Exp $

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

# The name of the test extension varies by operating system.
#
if {$::tcl_platform(platform) eq "windows"} {
  set testextension ./testloadext.dll
} else {
  set testextension ./libtestloadext.so
}

# Make sure the test extension actually exists.  If it does not
# exist, try to create it.  If unable to create it, then skip this
# test file.
#
if {![file exists $testextension]} {
  set srcdir [file dir $testdir]/src
  set testextsrc $srcdir/test_loadext.c
  if {[catch {
    exec gcc -shared $testextsrc -o $testextension
  } msg]} {
    puts "Skipping loadext tests: Test extension not built..."
    puts $msg
    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 testloadext_init
  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 testloadext_init
  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.
................................................................................
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 "${testextension}xx"
  } msg]
  list $rc $msg
} [list 1 [subst -nocommands \
  {unable to open shared library [${testextension}xx]}
]]

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

# 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 {
................................................................................
  set rc [catch {
    sqlite3_load_extension db $testextension testbrokenext_init
  } msg]
  list $rc $msg
} {1 {error during initialization: broken!}}

finish_test