169e777f3Sdanielk1977# 2006 July 14 269e777f3Sdanielk1977# 369e777f3Sdanielk1977# The author disclaims copyright to this source code. In place of 469e777f3Sdanielk1977# a legal notice, here is a blessing: 569e777f3Sdanielk1977# 669e777f3Sdanielk1977# May you do good and not evil. 769e777f3Sdanielk1977# May you find forgiveness for yourself and forgive others. 869e777f3Sdanielk1977# May you share freely, never taking more than you give. 969e777f3Sdanielk1977# 1069e777f3Sdanielk1977#*********************************************************************** 1169e777f3Sdanielk1977# This file implements regression tests for SQLite library. The 121409be69Sdrh# focus of this script is extension loading. 1369e777f3Sdanielk1977# 14eefa0003Sdanielk1977# $Id: loadext.test,v 1.17 2009/03/20 09:09:37 danielk1977 Exp $ 1569e777f3Sdanielk1977 1669e777f3Sdanielk1977set testdir [file dirname $argv0] 1769e777f3Sdanielk1977source $testdir/tester.tcl 1869e777f3Sdanielk1977 191e9daa6aSdrhifcapable !load_ext { 201e9daa6aSdrh finish_test 211e9daa6aSdrh return 221e9daa6aSdrh} 231e9daa6aSdrh 24428397c1Sdrh# The name of the test extension varies by operating system. 25428397c1Sdrh# 26f1c6bc5cSmistachkinif {$::tcl_platform(platform) eq "windows"} { 27428397c1Sdrh set testextension ./testloadext.dll 2869e777f3Sdanielk1977} else { 29428397c1Sdrh set testextension ./libtestloadext.so 3069e777f3Sdanielk1977} 31104d74c7Sdrhset gcc_shared "-shared -fPIC" 3263703a42Sdanielk1977if {$::tcl_platform(os) eq "Darwin"} { 3363703a42Sdanielk1977 set gcc_shared -dynamiclib 3463703a42Sdanielk1977} 3569e777f3Sdanielk1977 3698cab2c0Sdanielk1977# The error messages tested by this file are operating system dependent 3798cab2c0Sdanielk1977# (because they are returned by sqlite3OsDlError()). For now, they only 3898cab2c0Sdanielk1977# work with UNIX (and probably only certain kinds of UNIX). 3998cab2c0Sdanielk1977# 40c3f759bdSdanielk1977# When a shared-object cannot be opened because it does not exist, the 41c3f759bdSdanielk1977# format of the message returned is: 4298cab2c0Sdanielk1977# 43c3f759bdSdanielk1977# [format $dlerror_nosuchfile <shared-object-name>] 44c3f759bdSdanielk1977# 45c3f759bdSdanielk1977# When a shared-object cannot be opened because it consists of the 4 46c3f759bdSdanielk1977# characters "blah" only, we expect the error message to be: 47c3f759bdSdanielk1977# 48c3f759bdSdanielk1977# [format $dlerror_notadll <shared-object-name>] 4998cab2c0Sdanielk1977# 5098cab2c0Sdanielk1977# When a symbol cannot be found within an open shared-object, the error 5198cab2c0Sdanielk1977# message should be: 5298cab2c0Sdanielk1977# 5398cab2c0Sdanielk1977# [format $dlerror_nosymbol <shared-object-name> <symbol-name>] 5498cab2c0Sdanielk1977# 55c3f759bdSdanielk1977# The exact error messages are not important. The important bit is 56c3f759bdSdanielk1977# that SQLite is correctly copying the message from xDlError(). 57c3f759bdSdanielk1977# 58c3f759bdSdanielk1977set dlerror_nosuchfile \ 59c3f759bdSdanielk1977 {%s: cannot open shared object file: No such file or directory} 60c3f759bdSdanielk1977set dlerror_notadll {%s: file too short} 6198cab2c0Sdanielk1977set dlerror_nosymbol {%s: undefined symbol: %s} 6298cab2c0Sdanielk1977 6363703a42Sdanielk1977if {$::tcl_platform(os) eq "Darwin"} { 64*2d588b8cSdrh set dlerror_nosuchfile {dlopen.%s, 10.: .*image.*found.*} 65*2d588b8cSdrh set dlerror_notadll {dlopen.%1$s, 10.: .*image.*found.*} 66*2d588b8cSdrh set dlerror_nosymbol {dlsym.XXX, %2$s.: symbol not found} 6763703a42Sdanielk1977} 6863703a42Sdanielk1977 691925a2e6Smistachkinif {$::tcl_platform(platform) eq "windows"} { 701925a2e6Smistachkin set dlerror_nosuchfile {The specified module could not be found.*} 711925a2e6Smistachkin set dlerror_notadll {%%1 is not a valid Win32 application.*} 721925a2e6Smistachkin set dlerror_nosymbol {The specified procedure could not be found.*} 731925a2e6Smistachkin} 741925a2e6Smistachkin 75428397c1Sdrh# Make sure the test extension actually exists. If it does not 76428397c1Sdrh# exist, try to create it. If unable to create it, then skip this 77428397c1Sdrh# test file. 78428397c1Sdrh# 7969e777f3Sdanielk1977if {![file exists $testextension]} { 80428397c1Sdrh set srcdir [file dir $testdir]/src 81428397c1Sdrh set testextsrc $srcdir/test_loadext.c 82eefa0003Sdanielk1977 83eefa0003Sdanielk1977 set cmdline [concat exec gcc $gcc_shared] 84d7d19b71Sdan lappend cmdline -Wall -I$srcdir -I. -I.. -g $testextsrc -o $testextension 85eefa0003Sdanielk1977 86eefa0003Sdanielk1977 if {[catch $cmdline msg]} { 8769e777f3Sdanielk1977 puts "Skipping loadext tests: Test extension not built..." 88428397c1Sdrh puts $msg 8969e777f3Sdanielk1977 finish_test 9069e777f3Sdanielk1977 return 9169e777f3Sdanielk1977 } 92428397c1Sdrh} 9369e777f3Sdanielk1977 9469e777f3Sdanielk1977# Test that loading the extension produces the expected results - adding 9569e777f3Sdanielk1977# the half() function to the specified database handle. 9669e777f3Sdanielk1977# 9769e777f3Sdanielk1977do_test loadext-1.1 { 9869e777f3Sdanielk1977 catchsql { 9969e777f3Sdanielk1977 SELECT half(1.0); 10069e777f3Sdanielk1977 } 10169e777f3Sdanielk1977} {1 {no such function: half}} 10269e777f3Sdanielk1977do_test loadext-1.2 { 1034144905bSdrh db enable_load_extension 1 104428397c1Sdrh sqlite3_load_extension db $testextension testloadext_init 10569e777f3Sdanielk1977 catchsql { 10669e777f3Sdanielk1977 SELECT half(1.0); 10769e777f3Sdanielk1977 } 10869e777f3Sdanielk1977} {0 0.5} 10969e777f3Sdanielk1977 11069e777f3Sdanielk1977# Test that a second database connection (db2) can load the extension also. 11169e777f3Sdanielk1977# 11269e777f3Sdanielk1977do_test loadext-1.3 { 11369e777f3Sdanielk1977 sqlite3 db2 test.db 114f602a161Sdrh sqlite3_db_config db2 SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1 11569e777f3Sdanielk1977 catchsql { 11669e777f3Sdanielk1977 SELECT half(1.0); 11769e777f3Sdanielk1977 } db2 11869e777f3Sdanielk1977} {1 {no such function: half}} 11969e777f3Sdanielk1977do_test loadext-1.4 { 120428397c1Sdrh sqlite3_load_extension db2 $testextension testloadext_init 12169e777f3Sdanielk1977 catchsql { 12269e777f3Sdanielk1977 SELECT half(1.0); 12369e777f3Sdanielk1977 } db2 12469e777f3Sdanielk1977} {0 0.5} 12569e777f3Sdanielk1977 12669e777f3Sdanielk1977# Close the first database connection. Then check that the second database 12769e777f3Sdanielk1977# can still use the half() function without a problem. 12869e777f3Sdanielk1977# 12969e777f3Sdanielk1977do_test loadext-1.5 { 13069e777f3Sdanielk1977 db close 13169e777f3Sdanielk1977 catchsql { 13269e777f3Sdanielk1977 SELECT half(1.0); 13369e777f3Sdanielk1977 } db2 13469e777f3Sdanielk1977} {0 0.5} 13569e777f3Sdanielk1977 13669e777f3Sdanielk1977db2 close 13769e777f3Sdanielk1977sqlite3 db test.db 138c2e87a3eSdrhsqlite3_enable_load_extension db 1 13969e777f3Sdanielk1977 14069e777f3Sdanielk1977# Try to load an extension for which the file does not exist. 14169e777f3Sdanielk1977# 14269e777f3Sdanielk1977do_test loadext-2.1 { 143fda06befSmistachkin forcedelete ${testextension}xx 14469e777f3Sdanielk1977 set rc [catch { 145428397c1Sdrh sqlite3_load_extension db "${testextension}xx" 14669e777f3Sdanielk1977 } msg] 14769e777f3Sdanielk1977 list $rc $msg 148cca17c30Sdrh} /[list 1 [format $dlerror_nosuchfile ${testextension}xx.*]]/ 14969e777f3Sdanielk1977 15069e777f3Sdanielk1977# Try to load an extension for which the file is not a shared object 15169e777f3Sdanielk1977# 15269e777f3Sdanielk1977do_test loadext-2.2 { 153cca17c30Sdrh set fd [open "./notasharedlib.so" w] 154cca17c30Sdrh puts $fd blah 155cca17c30Sdrh close $fd 156cca17c30Sdrh set fd [open "./notasharedlib.dll" w] 15769e777f3Sdanielk1977 puts $fd blah 15869e777f3Sdanielk1977 close $fd 15969e777f3Sdanielk1977 set rc [catch { 160cca17c30Sdrh sqlite3_load_extension db "./notasharedlib" 16169e777f3Sdanielk1977 } msg] 162cca17c30Sdrh list $rc $msg 163cca17c30Sdrh} /[list 1 [format $dlerror_notadll ./notasharedlib.*]]/ 16469e777f3Sdanielk1977 16569e777f3Sdanielk1977# Try to load an extension for which the file is present but the 16669e777f3Sdanielk1977# entry point is not. 16769e777f3Sdanielk1977# 16869e777f3Sdanielk1977do_test loadext-2.3 { 16969e777f3Sdanielk1977 set rc [catch { 17069e777f3Sdanielk1977 sqlite3_load_extension db $testextension icecream 17169e777f3Sdanielk1977 } msg] 17263703a42Sdanielk1977 if {$::tcl_platform(os) eq "Darwin"} { 17363703a42Sdanielk1977 regsub {0x[1234567890abcdefABCDEF]*} $msg XXX msg 17463703a42Sdanielk1977 } 17569e777f3Sdanielk1977 list $rc $msg 1761925a2e6Smistachkin} /[list 1 [format $dlerror_nosymbol $testextension icecream]]/ 17769e777f3Sdanielk1977 17869e777f3Sdanielk1977# Try to load an extension for which the entry point fails (returns non-zero) 17969e777f3Sdanielk1977# 18069e777f3Sdanielk1977do_test loadext-2.4 { 18169e777f3Sdanielk1977 set rc [catch { 18269e777f3Sdanielk1977 sqlite3_load_extension db $testextension testbrokenext_init 18369e777f3Sdanielk1977 } msg] 18469e777f3Sdanielk1977 list $rc $msg 18569e777f3Sdanielk1977} {1 {error during initialization: broken!}} 18669e777f3Sdanielk1977 187fdb83b2fSdrh############################################################################ 188fdb83b2fSdrh# Tests for the load_extension() SQL function 189fdb83b2fSdrh# 190fdb83b2fSdrh 191fdb83b2fSdrhdb close 192fdb83b2fSdrhsqlite3 db test.db 193c2e87a3eSdrhsqlite3_enable_load_extension db 1 194fdb83b2fSdrhdo_test loadext-3.1 { 195fdb83b2fSdrh catchsql { 196fdb83b2fSdrh SELECT half(5); 197fdb83b2fSdrh } 198fdb83b2fSdrh} {1 {no such function: half}} 199fdb83b2fSdrhdo_test loadext-3.2 { 20063703a42Sdanielk1977 set res [catchsql { 201fdb83b2fSdrh SELECT load_extension($::testextension) 20263703a42Sdanielk1977 }] 20363703a42Sdanielk1977 if {$::tcl_platform(os) eq "Darwin"} { 20463703a42Sdanielk1977 regsub {0x[1234567890abcdefABCDEF]*} $res XXX res 205fdb83b2fSdrh } 20663703a42Sdanielk1977 set res 207cca17c30Sdrh} /[list 1 [format $dlerror_nosymbol $testextension sqlite3_.*_init]]/ 208fdb83b2fSdrhdo_test loadext-3.3 { 209fdb83b2fSdrh catchsql { 210fdb83b2fSdrh SELECT load_extension($::testextension,'testloadext_init') 211fdb83b2fSdrh } 212fdb83b2fSdrh} {0 {{}}} 213fdb83b2fSdrhdo_test loadext-3.4 { 214fdb83b2fSdrh catchsql { 215fdb83b2fSdrh SELECT half(5); 216fdb83b2fSdrh } 217fdb83b2fSdrh} {0 2.5} 218d72a8414Sdrhdo_test loadext-3.5 { 219d72a8414Sdrh db eval { 220d72a8414Sdrh SELECT sqlite3_status('MEMORY_USED') AS mused 221d72a8414Sdrh } break 222d72a8414Sdrh puts -nonewline " (memory_used=$mused) " 223d72a8414Sdrh expr {$mused>0} 224d72a8414Sdrh} {1} 225d72a8414Sdrhdo_test loadext-3.6 { 226d72a8414Sdrh catchsql { 227d72a8414Sdrh SELECT sqlite3_status('MEMORY_USED_X') AS mused 228d72a8414Sdrh } 229d72a8414Sdrh} {1 {unknown status property: MEMORY_USED_X}} 230d72a8414Sdrhdo_test loadext-3.7 { 231d72a8414Sdrh catchsql { 232d72a8414Sdrh SELECT sqlite3_status(4.53) AS mused 233d72a8414Sdrh } 234d72a8414Sdrh} {1 {unknown status type}} 235d72a8414Sdrhdo_test loadext-3.8 { 236d72a8414Sdrh catchsql { 237d72a8414Sdrh SELECT sqlite3_status(23) AS mused 238d72a8414Sdrh } 239d72a8414Sdrh} {1 {sqlite3_status(23,...) returns 21}} 240fdb83b2fSdrh 241c2e87a3eSdrh# Ticket #1863 242c2e87a3eSdrh# Make sure the extension loading mechanism will not work unless it 243c2e87a3eSdrh# is explicitly enabled. 244c2e87a3eSdrh# 245c2e87a3eSdrhdb close 246c2e87a3eSdrhsqlite3 db test.db 247c2e87a3eSdrhdo_test loadext-4.1 { 248c2e87a3eSdrh catchsql { 249c2e87a3eSdrh SELECT load_extension($::testextension,'testloadext_init') 250c2e87a3eSdrh } 251c2e87a3eSdrh} {1 {not authorized}} 252c2e87a3eSdrhdo_test loadext-4.2 { 253c2e87a3eSdrh sqlite3_enable_load_extension db 1 254c2e87a3eSdrh catchsql { 255c2e87a3eSdrh SELECT load_extension($::testextension,'testloadext_init') 256c2e87a3eSdrh } 257c2e87a3eSdrh} {0 {{}}} 258c2e87a3eSdrh 259f602a161Sdrh# disable all extension loading 260c2e87a3eSdrhdo_test loadext-4.3 { 261c2e87a3eSdrh sqlite3_enable_load_extension db 0 262c2e87a3eSdrh catchsql { 263c2e87a3eSdrh SELECT load_extension($::testextension,'testloadext_init') 264c2e87a3eSdrh } 265c2e87a3eSdrh} {1 {not authorized}} 266c2e87a3eSdrh 267f602a161Sdrh# enable C-api extension loading only. Show that the SQL function 268f602a161Sdrh# still does not work. 269f602a161Sdrhdo_test loadext-4.4 { 270f602a161Sdrh sqlite3_db_config db SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1 271f602a161Sdrh catchsql { 272f602a161Sdrh SELECT load_extension($::testextension,'testloadext_init') 273f602a161Sdrh } 274f602a161Sdrh} {1 {not authorized}} 275f602a161Sdrh 276701bb3b4Sdrhsource $testdir/malloc_common.tcl 277c2e87a3eSdrh 278c2e87a3eSdrh 279701bb3b4Sdrh# Malloc failure in sqlite3_auto_extension and sqlite3_load_extension 280701bb3b4Sdrh# 281701bb3b4Sdrhdo_malloc_test loadext-5 -tclprep { 282701bb3b4Sdrh sqlite3_reset_auto_extension 283701bb3b4Sdrh} -tclbody { 284701bb3b4Sdrh if {[autoinstall_test_functions]==7} {error "out of memory"} 285701bb3b4Sdrh} 2861925a2e6Smistachkin 2871925a2e6Smistachkin# On Windows, this malloc test must be skipped because the winDlOpen 2881925a2e6Smistachkin# function itself can fail due to "out of memory" conditions. 2891925a2e6Smistachkin# 2901925a2e6Smistachkinif {$::tcl_platform(platform) ne "windows"} { 291701bb3b4Sdrh do_malloc_test loadext-6 -tclbody { 292701bb3b4Sdrh db enable_load_extension 1 293701bb3b4Sdrh sqlite3_load_extension db $::testextension testloadext_init 294701bb3b4Sdrh } 2951925a2e6Smistachkin} 2961925a2e6Smistachkin 297701bb3b4Sdrhautoinstall_test_functions 298701bb3b4Sdrh 29969e777f3Sdanielk1977finish_test 300