danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 1 | # 2006 July 14 |
| 2 | # |
| 3 | # The author disclaims copyright to this source code. In place of |
| 4 | # a legal notice, here is a blessing: |
| 5 | # |
| 6 | # May you do good and not evil. |
| 7 | # May you find forgiveness for yourself and forgive others. |
| 8 | # May you share freely, never taking more than you give. |
| 9 | # |
| 10 | #*********************************************************************** |
| 11 | # This file implements regression tests for SQLite library. The |
drh | 1409be6 | 2006-08-23 20:07:20 +0000 | [diff] [blame] | 12 | # focus of this script is extension loading. |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 13 | # |
danielk1977 | eefa000 | 2009-03-20 09:09:37 +0000 | [diff] [blame] | 14 | # $Id: loadext.test,v 1.17 2009/03/20 09:09:37 danielk1977 Exp $ |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 15 | |
| 16 | set testdir [file dirname $argv0] |
| 17 | source $testdir/tester.tcl |
| 18 | |
drh | 1e9daa6 | 2007-04-06 21:42:22 +0000 | [diff] [blame] | 19 | ifcapable !load_ext { |
| 20 | finish_test |
| 21 | return |
| 22 | } |
| 23 | |
drh | 428397c | 2006-06-17 13:21:32 +0000 | [diff] [blame] | 24 | # The name of the test extension varies by operating system. |
| 25 | # |
mistachkin | f1c6bc5 | 2012-06-21 15:09:20 +0000 | [diff] [blame] | 26 | if {$::tcl_platform(platform) eq "windows"} { |
drh | 428397c | 2006-06-17 13:21:32 +0000 | [diff] [blame] | 27 | set testextension ./testloadext.dll |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 28 | } else { |
drh | 428397c | 2006-06-17 13:21:32 +0000 | [diff] [blame] | 29 | set testextension ./libtestloadext.so |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 30 | } |
drh | 104d74c | 2008-10-13 17:09:11 +0000 | [diff] [blame] | 31 | set gcc_shared "-shared -fPIC" |
danielk1977 | 63703a4 | 2008-06-30 15:09:29 +0000 | [diff] [blame] | 32 | if {$::tcl_platform(os) eq "Darwin"} { |
| 33 | set gcc_shared -dynamiclib |
| 34 | } |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 35 | |
danielk1977 | 98cab2c | 2007-09-01 05:57:49 +0000 | [diff] [blame] | 36 | # The error messages tested by this file are operating system dependent |
| 37 | # (because they are returned by sqlite3OsDlError()). For now, they only |
| 38 | # work with UNIX (and probably only certain kinds of UNIX). |
| 39 | # |
danielk1977 | c3f759b | 2007-09-01 06:19:05 +0000 | [diff] [blame] | 40 | # When a shared-object cannot be opened because it does not exist, the |
| 41 | # format of the message returned is: |
danielk1977 | 98cab2c | 2007-09-01 05:57:49 +0000 | [diff] [blame] | 42 | # |
danielk1977 | c3f759b | 2007-09-01 06:19:05 +0000 | [diff] [blame] | 43 | # [format $dlerror_nosuchfile <shared-object-name>] |
| 44 | # |
| 45 | # When a shared-object cannot be opened because it consists of the 4 |
| 46 | # characters "blah" only, we expect the error message to be: |
| 47 | # |
| 48 | # [format $dlerror_notadll <shared-object-name>] |
danielk1977 | 98cab2c | 2007-09-01 05:57:49 +0000 | [diff] [blame] | 49 | # |
| 50 | # When a symbol cannot be found within an open shared-object, the error |
| 51 | # message should be: |
| 52 | # |
| 53 | # [format $dlerror_nosymbol <shared-object-name> <symbol-name>] |
| 54 | # |
danielk1977 | c3f759b | 2007-09-01 06:19:05 +0000 | [diff] [blame] | 55 | # The exact error messages are not important. The important bit is |
| 56 | # that SQLite is correctly copying the message from xDlError(). |
| 57 | # |
| 58 | set dlerror_nosuchfile \ |
| 59 | {%s: cannot open shared object file: No such file or directory} |
| 60 | set dlerror_notadll {%s: file too short} |
| 61 | set dlerror_nosymbol {%s: undefined symbol: %s} |
danielk1977 | 98cab2c | 2007-09-01 05:57:49 +0000 | [diff] [blame] | 62 | |
danielk1977 | 63703a4 | 2008-06-30 15:09:29 +0000 | [diff] [blame] | 63 | if {$::tcl_platform(os) eq "Darwin"} { |
drh | 2d588b8 | 2018-11-17 14:59:35 +0000 | [diff] [blame] | 64 | set dlerror_nosuchfile {dlopen.%s, 10.: .*image.*found.*} |
| 65 | set dlerror_notadll {dlopen.%1$s, 10.: .*image.*found.*} |
| 66 | set dlerror_nosymbol {dlsym.XXX, %2$s.: symbol not found} |
danielk1977 | 63703a4 | 2008-06-30 15:09:29 +0000 | [diff] [blame] | 67 | } |
| 68 | |
mistachkin | 1925a2e | 2014-02-24 21:20:25 +0000 | [diff] [blame] | 69 | if {$::tcl_platform(platform) eq "windows"} { |
| 70 | set dlerror_nosuchfile {The specified module could not be found.*} |
| 71 | set dlerror_notadll {%%1 is not a valid Win32 application.*} |
| 72 | set dlerror_nosymbol {The specified procedure could not be found.*} |
| 73 | } |
| 74 | |
drh | 428397c | 2006-06-17 13:21:32 +0000 | [diff] [blame] | 75 | # Make sure the test extension actually exists. If it does not |
| 76 | # exist, try to create it. If unable to create it, then skip this |
| 77 | # test file. |
| 78 | # |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 79 | if {![file exists $testextension]} { |
drh | 428397c | 2006-06-17 13:21:32 +0000 | [diff] [blame] | 80 | set srcdir [file dir $testdir]/src |
| 81 | set testextsrc $srcdir/test_loadext.c |
danielk1977 | eefa000 | 2009-03-20 09:09:37 +0000 | [diff] [blame] | 82 | |
| 83 | set cmdline [concat exec gcc $gcc_shared] |
dan | d7d19b7 | 2016-08-01 16:50:50 +0000 | [diff] [blame] | 84 | lappend cmdline -Wall -I$srcdir -I. -I.. -g $testextsrc -o $testextension |
danielk1977 | eefa000 | 2009-03-20 09:09:37 +0000 | [diff] [blame] | 85 | |
| 86 | if {[catch $cmdline msg]} { |
drh | 428397c | 2006-06-17 13:21:32 +0000 | [diff] [blame] | 87 | puts "Skipping loadext tests: Test extension not built..." |
| 88 | puts $msg |
| 89 | finish_test |
| 90 | return |
| 91 | } |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | # Test that loading the extension produces the expected results - adding |
| 95 | # the half() function to the specified database handle. |
| 96 | # |
| 97 | do_test loadext-1.1 { |
| 98 | catchsql { |
| 99 | SELECT half(1.0); |
| 100 | } |
| 101 | } {1 {no such function: half}} |
| 102 | do_test loadext-1.2 { |
drh | 4144905 | 2006-07-06 17:08:48 +0000 | [diff] [blame] | 103 | db enable_load_extension 1 |
drh | 428397c | 2006-06-17 13:21:32 +0000 | [diff] [blame] | 104 | sqlite3_load_extension db $testextension testloadext_init |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 105 | catchsql { |
| 106 | SELECT half(1.0); |
| 107 | } |
| 108 | } {0 0.5} |
| 109 | |
| 110 | # Test that a second database connection (db2) can load the extension also. |
| 111 | # |
| 112 | do_test loadext-1.3 { |
| 113 | sqlite3 db2 test.db |
drh | f602a16 | 2016-04-21 01:58:21 +0000 | [diff] [blame] | 114 | sqlite3_db_config db2 SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1 |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 115 | catchsql { |
| 116 | SELECT half(1.0); |
| 117 | } db2 |
| 118 | } {1 {no such function: half}} |
| 119 | do_test loadext-1.4 { |
drh | 428397c | 2006-06-17 13:21:32 +0000 | [diff] [blame] | 120 | sqlite3_load_extension db2 $testextension testloadext_init |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 121 | catchsql { |
| 122 | SELECT half(1.0); |
| 123 | } db2 |
| 124 | } {0 0.5} |
| 125 | |
| 126 | # Close the first database connection. Then check that the second database |
| 127 | # can still use the half() function without a problem. |
| 128 | # |
| 129 | do_test loadext-1.5 { |
| 130 | db close |
| 131 | catchsql { |
| 132 | SELECT half(1.0); |
| 133 | } db2 |
| 134 | } {0 0.5} |
| 135 | |
| 136 | db2 close |
| 137 | sqlite3 db test.db |
drh | c2e87a3 | 2006-06-27 15:16:14 +0000 | [diff] [blame] | 138 | sqlite3_enable_load_extension db 1 |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 139 | |
| 140 | # Try to load an extension for which the file does not exist. |
| 141 | # |
| 142 | do_test loadext-2.1 { |
mistachkin | fda06be | 2011-08-02 00:57:34 +0000 | [diff] [blame] | 143 | forcedelete ${testextension}xx |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 144 | set rc [catch { |
drh | 428397c | 2006-06-17 13:21:32 +0000 | [diff] [blame] | 145 | sqlite3_load_extension db "${testextension}xx" |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 146 | } msg] |
| 147 | list $rc $msg |
drh | cca17c3 | 2013-04-19 12:32:52 +0000 | [diff] [blame] | 148 | } /[list 1 [format $dlerror_nosuchfile ${testextension}xx.*]]/ |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 149 | |
| 150 | # Try to load an extension for which the file is not a shared object |
| 151 | # |
| 152 | do_test loadext-2.2 { |
drh | cca17c3 | 2013-04-19 12:32:52 +0000 | [diff] [blame] | 153 | set fd [open "./notasharedlib.so" w] |
| 154 | puts $fd blah |
| 155 | close $fd |
| 156 | set fd [open "./notasharedlib.dll" w] |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 157 | puts $fd blah |
| 158 | close $fd |
| 159 | set rc [catch { |
drh | cca17c3 | 2013-04-19 12:32:52 +0000 | [diff] [blame] | 160 | sqlite3_load_extension db "./notasharedlib" |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 161 | } msg] |
drh | cca17c3 | 2013-04-19 12:32:52 +0000 | [diff] [blame] | 162 | list $rc $msg |
| 163 | } /[list 1 [format $dlerror_notadll ./notasharedlib.*]]/ |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 164 | |
| 165 | # Try to load an extension for which the file is present but the |
| 166 | # entry point is not. |
| 167 | # |
| 168 | do_test loadext-2.3 { |
| 169 | set rc [catch { |
| 170 | sqlite3_load_extension db $testextension icecream |
| 171 | } msg] |
danielk1977 | 63703a4 | 2008-06-30 15:09:29 +0000 | [diff] [blame] | 172 | if {$::tcl_platform(os) eq "Darwin"} { |
| 173 | regsub {0x[1234567890abcdefABCDEF]*} $msg XXX msg |
| 174 | } |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 175 | list $rc $msg |
mistachkin | 1925a2e | 2014-02-24 21:20:25 +0000 | [diff] [blame] | 176 | } /[list 1 [format $dlerror_nosymbol $testextension icecream]]/ |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 177 | |
| 178 | # Try to load an extension for which the entry point fails (returns non-zero) |
| 179 | # |
| 180 | do_test loadext-2.4 { |
| 181 | set rc [catch { |
| 182 | sqlite3_load_extension db $testextension testbrokenext_init |
| 183 | } msg] |
| 184 | list $rc $msg |
| 185 | } {1 {error during initialization: broken!}} |
| 186 | |
drh | fdb83b2 | 2006-06-17 14:12:47 +0000 | [diff] [blame] | 187 | ############################################################################ |
| 188 | # Tests for the load_extension() SQL function |
| 189 | # |
| 190 | |
| 191 | db close |
| 192 | sqlite3 db test.db |
drh | c2e87a3 | 2006-06-27 15:16:14 +0000 | [diff] [blame] | 193 | sqlite3_enable_load_extension db 1 |
drh | fdb83b2 | 2006-06-17 14:12:47 +0000 | [diff] [blame] | 194 | do_test loadext-3.1 { |
| 195 | catchsql { |
| 196 | SELECT half(5); |
| 197 | } |
| 198 | } {1 {no such function: half}} |
| 199 | do_test loadext-3.2 { |
danielk1977 | 63703a4 | 2008-06-30 15:09:29 +0000 | [diff] [blame] | 200 | set res [catchsql { |
drh | fdb83b2 | 2006-06-17 14:12:47 +0000 | [diff] [blame] | 201 | SELECT load_extension($::testextension) |
danielk1977 | 63703a4 | 2008-06-30 15:09:29 +0000 | [diff] [blame] | 202 | }] |
| 203 | if {$::tcl_platform(os) eq "Darwin"} { |
| 204 | regsub {0x[1234567890abcdefABCDEF]*} $res XXX res |
drh | fdb83b2 | 2006-06-17 14:12:47 +0000 | [diff] [blame] | 205 | } |
danielk1977 | 63703a4 | 2008-06-30 15:09:29 +0000 | [diff] [blame] | 206 | set res |
drh | cca17c3 | 2013-04-19 12:32:52 +0000 | [diff] [blame] | 207 | } /[list 1 [format $dlerror_nosymbol $testextension sqlite3_.*_init]]/ |
drh | fdb83b2 | 2006-06-17 14:12:47 +0000 | [diff] [blame] | 208 | do_test loadext-3.3 { |
| 209 | catchsql { |
| 210 | SELECT load_extension($::testextension,'testloadext_init') |
| 211 | } |
| 212 | } {0 {{}}} |
| 213 | do_test loadext-3.4 { |
| 214 | catchsql { |
| 215 | SELECT half(5); |
| 216 | } |
| 217 | } {0 2.5} |
drh | d72a841 | 2008-06-19 15:44:00 +0000 | [diff] [blame] | 218 | do_test loadext-3.5 { |
| 219 | db eval { |
| 220 | SELECT sqlite3_status('MEMORY_USED') AS mused |
| 221 | } break |
| 222 | puts -nonewline " (memory_used=$mused) " |
| 223 | expr {$mused>0} |
| 224 | } {1} |
| 225 | do_test loadext-3.6 { |
| 226 | catchsql { |
| 227 | SELECT sqlite3_status('MEMORY_USED_X') AS mused |
| 228 | } |
| 229 | } {1 {unknown status property: MEMORY_USED_X}} |
| 230 | do_test loadext-3.7 { |
| 231 | catchsql { |
| 232 | SELECT sqlite3_status(4.53) AS mused |
| 233 | } |
| 234 | } {1 {unknown status type}} |
| 235 | do_test loadext-3.8 { |
| 236 | catchsql { |
| 237 | SELECT sqlite3_status(23) AS mused |
| 238 | } |
| 239 | } {1 {sqlite3_status(23,...) returns 21}} |
drh | fdb83b2 | 2006-06-17 14:12:47 +0000 | [diff] [blame] | 240 | |
drh | c2e87a3 | 2006-06-27 15:16:14 +0000 | [diff] [blame] | 241 | # Ticket #1863 |
| 242 | # Make sure the extension loading mechanism will not work unless it |
| 243 | # is explicitly enabled. |
| 244 | # |
| 245 | db close |
| 246 | sqlite3 db test.db |
| 247 | do_test loadext-4.1 { |
| 248 | catchsql { |
| 249 | SELECT load_extension($::testextension,'testloadext_init') |
| 250 | } |
| 251 | } {1 {not authorized}} |
| 252 | do_test loadext-4.2 { |
| 253 | sqlite3_enable_load_extension db 1 |
| 254 | catchsql { |
| 255 | SELECT load_extension($::testextension,'testloadext_init') |
| 256 | } |
| 257 | } {0 {{}}} |
| 258 | |
drh | f602a16 | 2016-04-21 01:58:21 +0000 | [diff] [blame] | 259 | # disable all extension loading |
drh | c2e87a3 | 2006-06-27 15:16:14 +0000 | [diff] [blame] | 260 | do_test loadext-4.3 { |
| 261 | sqlite3_enable_load_extension db 0 |
| 262 | catchsql { |
| 263 | SELECT load_extension($::testextension,'testloadext_init') |
| 264 | } |
| 265 | } {1 {not authorized}} |
| 266 | |
drh | f602a16 | 2016-04-21 01:58:21 +0000 | [diff] [blame] | 267 | # enable C-api extension loading only. Show that the SQL function |
| 268 | # still does not work. |
| 269 | do_test loadext-4.4 { |
| 270 | sqlite3_db_config db SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1 |
| 271 | catchsql { |
| 272 | SELECT load_extension($::testextension,'testloadext_init') |
| 273 | } |
| 274 | } {1 {not authorized}} |
| 275 | |
drh | 701bb3b | 2008-08-02 03:50:39 +0000 | [diff] [blame] | 276 | source $testdir/malloc_common.tcl |
drh | c2e87a3 | 2006-06-27 15:16:14 +0000 | [diff] [blame] | 277 | |
| 278 | |
drh | 701bb3b | 2008-08-02 03:50:39 +0000 | [diff] [blame] | 279 | # Malloc failure in sqlite3_auto_extension and sqlite3_load_extension |
| 280 | # |
| 281 | do_malloc_test loadext-5 -tclprep { |
| 282 | sqlite3_reset_auto_extension |
| 283 | } -tclbody { |
| 284 | if {[autoinstall_test_functions]==7} {error "out of memory"} |
| 285 | } |
mistachkin | 1925a2e | 2014-02-24 21:20:25 +0000 | [diff] [blame] | 286 | |
| 287 | # On Windows, this malloc test must be skipped because the winDlOpen |
| 288 | # function itself can fail due to "out of memory" conditions. |
| 289 | # |
| 290 | if {$::tcl_platform(platform) ne "windows"} { |
| 291 | do_malloc_test loadext-6 -tclbody { |
| 292 | db enable_load_extension 1 |
| 293 | sqlite3_load_extension db $::testextension testloadext_init |
| 294 | } |
drh | 701bb3b | 2008-08-02 03:50:39 +0000 | [diff] [blame] | 295 | } |
mistachkin | 1925a2e | 2014-02-24 21:20:25 +0000 | [diff] [blame] | 296 | |
drh | 701bb3b | 2008-08-02 03:50:39 +0000 | [diff] [blame] | 297 | autoinstall_test_functions |
| 298 | |
danielk1977 | 69e777f | 2006-06-14 10:38:02 +0000 | [diff] [blame] | 299 | finish_test |