1
0
Fork 0
mirror of https://github.com/DBD-SQLite/DBD-SQLite synced 2025-06-07 14:19:10 -04:00

Compare commits

...

279 commits
1.56 ... master

Author SHA1 Message Date
Kenichi Ishigaki
60515b30f8 Release 1.76 2024-10-19 13:46:02 +09:00
Kenichi Ishigaki
6f99c8ce41 Release 1.75_01 2024-09-17 23:04:35 +09:00
Kenichi Ishigaki
db7ea91d83 Bump bundled SQLite to 3.46.1 2024-09-17 22:54:53 +09:00
Kenichi Ishigaki
4ac600434f
Merge pull request #115 from sisyphus/win32_quadmath
Fix for Windows quadmath builds.
2024-09-17 22:50:16 +09:00
Kenichi Ishigaki
41957ce749
Merge pull request #116 from DBD-SQLite/use_checkout_v4
Use checkout v4
2024-09-17 22:48:10 +09:00
Kenichi Ishigaki
29167a0d65 Use buster images for older perls 2024-09-17 22:43:35 +09:00
Kenichi Ishigaki
fb80b73a8a Use checkout@v4 2024-09-17 22:37:20 +09:00
sisyphus
c5374438f4 dbdimp.c - Fix for Windows quadmath builds. 2024-09-17 22:03:29 +10:00
Kenichi Ishigaki
2ab93a4e41 Update constants 2024-03-17 22:32:36 +09:00
Kenichi Ishigaki
3e8df90227 Bump bundled SQLite to 3.45.2 2024-03-17 22:32:19 +09:00
Kenichi Ishigaki
b433d17436 Update SQLiteUtil 2024-03-17 22:31:23 +09:00
Kenichi Ishigaki
9014dd6f35
Merge pull request #112 from DBD-SQLite/fix/omit_load_extension_if_static
Omit load_extension if static perl
2024-03-17 22:18:46 +09:00
Kenichi Ishigaki
922c82b0ea Omit load_extension if static perl 2024-03-17 22:08:52 +09:00
Kenichi Ishigaki
01615f8630 Bump SQLite to 3.44.0 2023-11-03 15:08:24 +09:00
Kenichi Ishigaki
fea0e3268f Release 1.74 2023-09-20 02:24:48 +09:00
Kenichi Ishigaki
d4bb44460f Release 1.73_01 2023-07-09 10:03:24 +09:00
Kenichi Ishigaki
f9e3cb6b75 Update constants 2023-07-09 10:02:25 +09:00
Kenichi Ishigaki
3f66a57dd4 Update SQLiteUtil 2023-07-09 10:02:11 +09:00
Kenichi Ishigaki
7e63e18472 Bump sqlite3 from 3.41.0 to 3.42.0 2023-07-09 09:57:07 +09:00
Kenichi Ishigaki
c08f3400e8 Add a new constant 2023-02-23 11:20:23 +09:00
Kenichi Ishigaki
f764a74395 Upgrade SQLite to 3.41.0 2023-02-23 11:19:58 +09:00
Kenichi Ishigaki
ad5125d99d Ignore newly-added prepared_statement_scan_status constants 2023-02-23 11:19:14 +09:00
Kenichi Ishigaki
dd62355f48 Add year 2023 condition 2023-02-23 11:18:55 +09:00
Kenichi Ishigaki
0dc561d920
Merge pull request #105 from dboehmer/patch-1
Add missing possible table_type values to POD
2022-11-13 03:06:42 +09:00
Daniel Böhmer
1f413acd88 Add missing possible table_type values to POD
I noticed that table_info() returns table_types that are not listed in POD.
This copies every possible value from the SQLite documentation.
'LOCAL TEMPORARY' and 'SYSTEM TABLE' are not mentioned there
but come from SQLite.pm.

SQLite documentation on possible values:
https://www.sqlite.org/schematab.html#interpretation_of_the_schema_table
2022-11-12 18:42:30 +01:00
Kenichi Ishigaki
38e116df3f Release 1.72 2022-11-04 01:27:49 +09:00
Kenichi Ishigaki
a7e5af7397 Release 1.71_07 2022-10-26 03:35:56 +09:00
Kenichi Ishigaki
bacb65a77e Upgrade SQLite to 3.39.4 2022-10-26 03:33:21 +09:00
Kenichi Ishigaki
353f185cc5 Release 1.71_06 2022-03-12 11:51:36 +09:00
Kenichi Ishigaki
b03fd9980e
Merge pull request #99 from DBD-SQLite/set_utf8cache
Set UTF8CACHE to avoid slowdown with -DDEBUGGING
2022-03-12 11:49:24 +09:00
Kenichi Ishigaki
9c6cbfcc51 Set UTF8CACHE to avoid slowdown with -DDEBUGGING 2022-03-12 10:43:05 +09:00
Kenichi Ishigaki
fc64c4688a Release 1.71_05 2022-02-26 11:38:46 +09:00
Kenichi Ishigaki
687290909c
Merge pull request #97 from DBD-SQLite/lowercase_datatype
Lowercase datatype
2022-02-26 11:33:51 +09:00
Kenichi Ishigaki
b6a4eb43a7 THX 2022-02-26 11:28:39 +09:00
Kenichi Ishigaki
abc241d711 Lowercase datatype 2022-02-26 11:20:41 +09:00
Kenichi Ishigaki
2d595f3bf2 Tidy 2022-02-26 11:19:26 +09:00
Kenichi Ishigaki
27dfab4fb2 Revert "Tidy"
This reverts commit 4a4f5d599b.
2022-02-26 11:14:13 +09:00
Kenichi Ishigaki
4a4f5d599b Tidy 2022-02-26 11:08:36 +09:00
Kenichi Ishigaki
1a3baef06d xFunc must also be NULL to delete a function 2022-02-26 11:05:54 +09:00
Kenichi Ishigaki
0edf878de0 Release 1.71_04 2022-02-26 09:57:40 +09:00
Kenichi Ishigaki
b7f24e3e1d Pass PL_sv_undef instead of NULL 2022-02-26 09:56:10 +09:00
Kenichi Ishigaki
b7c98ea81b Release 1.71_03 2022-02-23 19:45:30 +09:00
Kenichi Ishigaki
d4aea379d4 Add sqlite_error_offset 2022-02-23 19:43:21 +09:00
Kenichi Ishigaki
6d0744549a Update SQLite to 3.38.0 2022-02-23 19:37:15 +09:00
Kenichi Ishigaki
01077fa8a3 Release 1.71_02 2022-01-07 05:50:25 +09:00
Kenichi Ishigaki
30a08cebd1 Update SQLite to 3.37.2 2022-01-07 05:48:22 +09:00
Kenichi Ishigaki
1bfcf7c38e Add 2022 to SQLiteUtil::year 2022-01-07 05:48:02 +09:00
Kenichi Ishigaki
4266881e66 Update Changes 2021-12-15 06:55:08 +09:00
Kenichi Ishigaki
f278c800b3
Merge pull request #94 from d-lamb/patch-1
Clarify which method to use when loading extension
2021-12-15 06:49:28 +09:00
Derek Lamb
5fde7cf0d1
Clarify which method to use when loading extension
Loading an extension using "select" statements does not work if the extension provides new functions.  But the extension given as an example in sqlite_enable_load_extension, libsqlitefunctions.so, does define functions, so loading that particular (very commonly used) extension with a "select" statement will not work.  I changed the example in sqlite_enable_load_extension to an extension that does not provide new functions, clarified the description of sqlite_load_extension, and added the libsqlitefunctions.so example to the description of sqlite_load_extension.
2021-12-14 14:30:50 -07:00
Kenichi Ishigaki
d465ea9219 Release 1.71_01 2021-12-02 02:00:43 +09:00
Kenichi Ishigaki
3b75eb3796 Hide SESSION_OBJCONFIG_SIZE 2021-12-02 01:39:35 +09:00
Kenichi Ishigaki
8bf916dbd7 Let create_function unregister an existing function 2021-12-02 01:32:01 +09:00
Kenichi Ishigaki
7848525aeb Update constants 2021-12-02 01:28:49 +09:00
Kenichi Ishigaki
ba4f472e73 Tweak for 3.37.0 2021-12-02 01:25:48 +09:00
Kenichi Ishigaki
d83bd84606 Update SQLite to 3.37.0 2021-12-02 01:25:24 +09:00
Kenichi Ishigaki
951617af45 Update Changes 2021-08-03 21:51:50 +09:00
Kenichi Ishigaki
428148d2cd
Merge pull request #90 from HaraldJoerg/utf_pod
Fix accented characters in SQLite.pm's POD
2021-08-03 21:50:14 +09:00
Harald Jörg
b4a573259f Fix accented characters in SQLite.pm's POD 2021-08-03 13:55:13 +02:00
Kenichi Ishigaki
711f90b8c7
Merge pull request #89 from FGasper/fix_sqlite_unicode_pod
Remove mention of now-deprecated “sqlite_unicode” parameter.
2021-08-03 10:40:08 +09:00
Felipe Gasper
ab0022890a Remove mention of now-deprecated “sqlite_unicode” parameter. 2021-08-02 20:49:33 -04:00
Kenichi Ishigaki
87e1545ccb Release 1.70 2021-08-01 19:20:26 +09:00
Kenichi Ishigaki
631cc94f17 Release 1.69_02 2021-07-30 23:18:42 +09:00
Kenichi Ishigaki
f949de6ab6 Fix an encoding issue of naive 2021-07-30 23:17:55 +09:00
Kenichi Ishigaki
0a455850e8 Fix doc that uses string_mode without the sqlite_ prefix (#86) 2021-07-30 23:12:04 +09:00
Kenichi Ishigaki
43225fd7eb No need to check unicode twice 2021-07-30 23:09:47 +09:00
Kenichi Ishigaki
6bac0136b3 Release 1.69_01 2021-07-30 06:07:43 +09:00
Kenichi Ishigaki
6e7986e8d4 Silence the deprecation warning of sqlite_unicode as it's so widely used 2021-07-30 06:05:13 +09:00
Kenichi Ishigaki
0f476b9904 Fix typo (#85) 2021-07-26 11:43:57 +09:00
Kenichi Ishigaki
d2abfe2752 Release 1.68 2021-07-22 14:28:47 +09:00
Kenichi Ishigaki
95a360a6a4 Release 1.67_07 2021-06-19 09:56:55 +09:00
Kenichi Ishigaki
f587238ff3 Update SQLite to 3.36.0 2021-06-19 09:49:56 +09:00
Kenichi Ishigaki
a7e04d785c Release 1.67_06 2021-06-14 12:48:15 +09:00
Kenichi Ishigaki
1aaf18dbf7 Experiment with quadmath patch from Tux to see if it works with older version of FreeBSD 2021-06-14 12:46:37 +09:00
Kenichi Ishigaki
076a7fd814 Release 1.67_05 2021-06-13 08:38:29 +09:00
Kenichi Ishigaki
fd0ecce1b0 Tweak doc 2021-06-06 01:56:56 +09:00
Kenichi Ishigaki
f14744d31a Use imported constants 2021-06-06 01:53:52 +09:00
Kenichi Ishigaki
9e59c780a7 Update Changes 2021-05-31 08:33:58 +09:00
Kenichi Ishigaki
dddc12423a Make DBD_SQLITE_STRING_MODE_ constants exportable 2021-05-31 08:31:22 +09:00
Kenichi Ishigaki
5c7779f889 Release 1.67_04 2021-05-31 07:53:52 +09:00
Kenichi Ishigaki
791eaba2ac Fix a leak 2021-05-30 22:41:48 +09:00
Kenichi Ishigaki
77f897da5a For ASAN testing 2021-05-30 22:41:37 +09:00
Kenichi Ishigaki
20782166cf Tweak constants.pl 2021-05-30 21:25:28 +09:00
Kenichi Ishigaki
0557f8d315 Update SQLite to 3.35.5 2021-05-30 21:24:14 +09:00
Kenichi Ishigaki
1dc2e1dbe2 Fix to use string_mode 2021-05-30 21:19:18 +09:00
Kenichi Ishigaki
31483a245f Merge branch 'string_mode' 2021-05-30 21:18:42 +09:00
Kenichi Ishigaki
57d2dd7fb5
Merge pull request #76 from DBD-SQLite/#75_fix_fts3_offsets
#75 fix fts3 offsets
2021-05-30 20:44:46 +09:00
Felipe Gasper
9dc75eaead Replace “string_unicode” boolean with “string_mode” enum.
Issue #78 and issue #68: This introduces additional, more robust
schemas for translating strings between SQLite and Perl.
2021-05-29 19:19:58 -04:00
dami
a512146d47 fix #74 -- add a dependency from dbdimp.o to the *.inc files included into dbdimp.c 2021-05-13 19:35:52 +02:00
dami
6669dbc332 cleanup tokenizer code and test 2021-05-13 12:27:57 +02:00
dami
80c7c91ae6 better variable names and comments 2021-05-11 09:40:24 +02:00
dami
f68f79415f test to show that perl tokenizer with unicode is extremely slow 2021-05-11 09:01:59 +02:00
dami
8d5a28cf5c additional test for snippet() 2021-05-09 22:22:39 +02:00
dami
b5c3f9d528 fixed #75 -- lastCharOffset must copy the OLD value of piEndOffset, BEFORE it is recomputed
also fixed 43_fts3.t so that it uses \p{Word} instead of \w, because en-us locale did not handle accented characters
2021-05-09 22:06:28 +02:00
dami
be9f64b2c9 tests for functions snippet() and offets() 2021-05-09 19:25:27 +02:00
Kenichi Ishigaki
aa90eee3a0
Merge pull request #67 from FGasper/fix_svpv_downgrade
Give upgraded strings to SQLite as downgraded when sqlite_unicode==0.
2021-04-25 22:30:53 +09:00
Kenichi Ishigaki
6c4d96adfe Typo 2021-04-18 08:46:11 +09:00
Kenichi Ishigaki
f066bb49ad
Merge pull request #72 from pullhub/sqlite_load_extension-vs-threadsafe
Note conflict between SQLITE_THREADSAFE default and extensions in POD
2021-04-17 22:48:33 +09:00
Bjoern Hoehrmann
0c6d966f1c Note conflict between SQLITE_THREADSAFE default and extensions that need sqlite3_mutex_* functions 2021-04-17 14:13:48 +02:00
Kenichi Ishigaki
768d3a99d2 Update Changes 2021-04-17 18:53:28 +09:00
Kenichi Ishigaki
2cd3f0cb20
Merge pull request #71 from DBD-SQLite/check_pthreads
Check pthreads
2021-04-17 18:49:26 +09:00
Kenichi Ishigaki
cedc9d4657 Test with a few more perls 2021-04-17 18:38:00 +09:00
Kenichi Ishigaki
8861380590 Set THREADSAFE=0 only if usethreads is undef and pthreads is not linked 2021-04-17 18:37:44 +09:00
Kenichi Ishigaki
797b724b43 Revert "Do not force THREADSAFE=0 when perl does not have usethreads (fix #69)"
This reverts commit b56f872c82.
2021-04-17 18:30:10 +09:00
Kenichi Ishigaki
b56f872c82 Do not force THREADSAFE=0 when perl does not have usethreads (fix #69) 2021-04-17 14:24:16 +09:00
Kenichi Ishigaki
020bc9062f Update SQLite to 3.35.4 2021-04-17 14:04:50 +09:00
Felipe Gasper
f1342ec177 Give upgraded strings to SQLite as downgraded when sqlite_unicode==0.
Issue #66: If $a and $b contain the same code points but one is upgraded
and the other isn’t, previously DBD::SQLite would give two different C
strings to SQLite. This changeset fixes that so that SQLite always
translates equivalent Perl strings to the same C string, regardless of the
Perl strings’ internal encoding.
2021-03-31 20:33:57 -04:00
Kenichi Ishigaki
e455116b51 Release 1.67_03 2021-03-31 06:35:06 +09:00
Kenichi Ishigaki
b045ba29b8 Use NVff (Tux++, leont++) #65 2021-03-31 06:30:45 +09:00
Kenichi Ishigaki
7fcca420ba Apply a patch for t/rt_73787_exponential_buffer_overflow.t (Tux++) #64 2021-03-31 06:23:36 +09:00
Kenichi Ishigaki
7bfec13b7e Enable math functions introduced in SQLite 3.35.0 2021-03-31 06:22:27 +09:00
Kenichi Ishigaki
4a81dcf4c7 Upgrade SQLite to 3.35.3 2021-03-31 06:22:09 +09:00
Kenichi Ishigaki
c15f5c5d4f Support versions released in 2021 2021-03-31 06:21:40 +09:00
Kenichi Ishigaki
3dff252633 Use https 2021-03-31 06:21:08 +09:00
Kenichi Ishigaki
242d674a55 Release 1.67_02 2020-12-06 02:04:08 +09:00
Kenichi Ishigaki
2db48b8ca1 Update Changes 2020-12-06 02:01:55 +09:00
Kenichi Ishigaki
4d1b28c393 Expose sqlite3_txn_state 2020-12-06 02:00:27 +09:00
Kenichi Ishigaki
fa6fa30878 Add a few constants 2020-12-06 01:59:56 +09:00
Kenichi Ishigaki
09278cad8e Updated SQLite to 3.34.0 2020-12-05 18:19:38 +09:00
Kenichi Ishigaki
e51324a7a3 Release 1.67_01 2020-11-24 21:57:43 +09:00
Kenichi Ishigaki
9eb89925a8 Add reporter's id 2020-11-24 21:53:18 +09:00
Kenichi Ishigaki
dd6ab32da9 Use av_fetch instead of av_shift, to avoid leaks 2020-11-23 21:41:57 +09:00
Kenichi Ishigaki
c5cce9f54f Strawberry perl seems to be installed already 2020-11-23 21:25:54 +09:00
Kenichi Ishigaki
d380158688 Use quadmath_snprintf if USE_QUADMATH is defined 2020-11-23 21:16:26 +09:00
Kenichi Ishigaki
7c01d15368 Update Changes 2020-11-06 06:16:07 +09:00
Kenichi Ishigaki
bd949a1c5d
Merge pull request #63 from toddr/foo
Switch to XSLoader
2020-11-06 06:14:28 +09:00
Todd Rinaldo
077ce52491 Switch to XSLoader 2020-11-05 10:54:42 -06:00
Kenichi Ishigaki
f6f75fa325 Update SQLite to 3.33.0 2020-08-30 11:16:42 +09:00
Kenichi Ishigaki
108b4a9b54 Release 1.66 2020-08-30 11:12:12 +09:00
Kenichi Ishigaki
3e91167b0c Release 1.65_03 2020-07-27 01:41:36 +09:00
Kenichi Ishigaki
4d7d00544e Update constants 2020-07-27 01:36:35 +09:00
Kenichi Ishigaki
9159838d96 Updated SQLite to 3.32.3 2020-07-27 01:36:01 +09:00
Kenichi Ishigaki
3dfcbcd8f1 Release 1.65_02 2020-02-08 22:00:34 +09:00
Kenichi Ishigaki
28cb59487f Update constants 2020-02-08 20:07:50 +09:00
Kenichi Ishigaki
a47cb92cfd Update SQLite to 3.31.1 2020-02-08 20:01:49 +09:00
Kenichi Ishigaki
d958b05c1d Release 1.65_01 2020-01-18 10:53:56 +09:00
Kenichi Ishigaki
5797c5a462 Merge branch 'workflow' 2020-01-18 10:53:30 +09:00
Kenichi Ishigaki
ccf4afe0f4 Test only 5.8 and the latest 2020-01-18 10:53:18 +09:00
Kenichi Ishigaki
07367324c5 Add yaml files for windows and mac 2020-01-18 10:46:34 +09:00
Kenichi Ishigaki
35902ff85a Simply build.yml 2020-01-18 10:42:23 +09:00
Kenichi Ishigaki
893dcfeb80 Add cpanfile 2020-01-18 10:36:06 +09:00
Kenichi Ishigaki
f367353b6a Add a workflow yaml 2020-01-18 10:32:00 +09:00
Kenichi Ishigaki
5f5caa286f Add more tests for create_function 2020-01-18 10:01:33 +09:00
Kenichi Ishigaki
2e455b0861 Add a note on the return value of a function for create_function 2020-01-18 10:01:07 +09:00
Kenichi Ishigaki
0cbc86a243 update constants 2019-10-27 23:53:30 +09:00
Kenichi Ishigaki
3565afd633 update SQLite to 3.30.1 2019-10-27 23:50:13 +09:00
Kenichi Ishigaki
8b3a041003 initialize eof (fix #55) 2019-08-18 20:12:51 +09:00
Kenichi Ishigaki
ccd1995967
Merge pull request #57 from pali/master
Add DBI SQL_BOOLEAN type as alias for SQLITE_INTEGER
2019-08-16 22:48:13 +09:00
Pali
6cffbab90e Add DBI SQL_BOOLEAN type as alias for SQLITE_INTEGER
According to SQLite documentation, boolean values are stored as integers:
https://www.sqlite.org/datatype3.html#boolean_datatype
2019-08-16 15:27:48 +02:00
Kenichi Ishigaki
583b5b131e
Merge pull request #56 from pali/master
Add DBI SQL_BIT, SQL_BINARY, SQL_VARBINARY and SQL_LONGVARBINARY types as alias for SQLITE_BLOB
2019-08-16 22:25:43 +09:00
Pali
012ad14605 Add DBI SQL_BIT, SQL_BINARY, SQL_VARBINARY and SQL_LONGVARBINARY types as alias for SQLITE_BLOB
Other DBI drivers use DBI SQL_VARBINARY type for binary data, including
SQLite3 ODBC driver (via DBD::ODBC). So this change allows to use DBI
SQL_VARBINARY type for SQLite3 blob data.
2019-08-16 14:41:37 +02:00
Kenichi Ishigaki
523d5a91ee
Merge pull request #54 from ppisar/undefined_filename
Initialize filename variable in sqlite_db_filename()
2019-08-12 12:03:30 +03:00
Kenichi Ishigaki
dd68440d7d Merge branch 'allow_created_function_to_return_blob' 2019-08-12 18:02:30 +09:00
Kenichi Ishigaki
1bab5016df release 1.64 2019-08-12 18:01:57 +09:00
Kenichi Ishigaki
64e4c9d299 Use trusty to test 2019-07-30 00:26:47 +09:00
Petr Písař
0c92dbae92 Initialize filename variable in sqlite_db_filename()
If sqlite library is too old, filename variable in
sqlite_db_filename() function was never defined. In spite of that the
variable was used in later condition.

This patch fixes it.
2019-07-29 16:59:44 +02:00
Kenichi Ishigaki
13f3416e3c allow created function to return [value, sql_type] to specify the value is a blob explicitly 2019-07-21 01:50:33 +09:00
Kenichi Ishigaki
3212d33b59 release 1.63_05 2019-07-12 02:47:53 +09:00
Kenichi Ishigaki
de43ac98af let db_config allow new constants 2019-07-12 02:44:45 +09:00
Kenichi Ishigaki
3363414db3 expose sqlite3_get_autocommit (fix #52) 2019-07-12 02:01:41 +09:00
Kenichi Ishigaki
e0aba4fb86 update constants 2019-07-12 01:14:05 +09:00
Kenichi Ishigaki
83885adae4 updated SQLite to 3.29.0 2019-07-12 01:09:18 +09:00
Kenichi Ishigaki
685c944cb5 release 1.63_04 2019-05-25 01:39:09 +09:00
Kenichi Ishigaki
e3bce4ab39 fix $dbh->quote(blob, SQL_BLOB) #51 2019-05-25 01:33:09 +09:00
Kenichi Ishigaki
f9a8feccc0 updated Changes 2019-05-23 03:43:36 +09:00
Kenichi Ishigaki
d4de22088c sqlite_db_filename may return an empty string or undef, dependeing on the situation (fix #50) 2019-05-23 03:31:31 +09:00
Kenichi Ishigaki
a9c7c5131a updated SQLite to 3.28.0 2019-04-18 00:40:25 +09:00
Kenichi Ishigaki
885fded4b6 updated SQLite to 3.27.2 2019-03-05 00:21:10 +09:00
Kenichi Ishigaki
dd9df3efea release 1.63_03 2019-02-15 01:55:00 +09:00
Kenichi Ishigaki
8b758bfbbf applied a patch to fix segmentation fault on 32-bit big-endian platforms by Niko Tyni (#45)
https://salsa.debian.org/perl-team/modules/packages/libdbd-sqlite3-perl/blob/master/debian/patches/0001-Fix-SQLITE_DBCONFIG_DEFENSIVE-parameter-types.patch
2019-02-15 01:52:05 +09:00
Kenichi Ishigaki
6e89c499b4 release 1.63_02 2019-02-14 04:08:12 +09:00
Kenichi Ishigaki
31915d44ed skip a compatibility test if sqlite is compiled with SQLITE_USE_URI (#47) 2019-02-14 03:28:15 +09:00
Kenichi Ishigaki
e76abc2774 updated SQLite to 3.27.1 2019-02-11 21:51:16 +09:00
Kenichi Ishigaki
82cdba9f8f fixed SQLiteUtil to fetch releases in 2019 2019-02-11 21:50:43 +09:00
Kenichi Ishigaki
ce5b33b381 try not to reuse hv 2019-01-26 07:41:16 +09:00
Kenichi Ishigaki
13da736ed6 release 1.63_01 2019-01-26 07:19:04 +09:00
Kenichi Ishigaki
b0fad50e4c fixed for older DBI 2019-01-26 07:12:40 +09:00
Kenichi Ishigaki
fa6a2c7040 fixed no if conditions 2019-01-26 07:10:10 +09:00
Kenichi Ishigaki
90ec098f1c added a boilerplace for test 2019-01-26 06:56:16 +09:00
Kenichi Ishigaki
7347e226a3
Merge pull request #46 from Corion/master
Handle 'unknown' op in DBD::SQLite::VirtualTable::PerlData
2019-01-26 06:51:52 +09:00
Kenichi Ishigaki
e5f82badfe initialize HV* with NULL 2019-01-26 06:37:26 +09:00
Max Maischein
1fd1a0d15f Handle 'unknown' op in DBD::SQLite::VirtualTable::PerlData
This patch adds code and a test when SQLite generates an 'unknown'
op for a table join in the BEST_INDEX() callback. The Perl code crashed
when such an op was generated for a JOIN criterion by the SQLite engine.

The SQLite engine creates an 'unknown' op on the following SQL
for example:

                select r.nodepath
                  from temp.scan_results r
                       left join temp.scan_results m
                             on r.nodepath = m.nodepath+1
                 where m.nodepath is null

The important part is that the right side of the left join must be
checked for IS NULL.
2019-01-25 19:05:07 +01:00
Kenichi Ishigaki
bfe71db88f locale warning is only available for perl 5.22+ 2019-01-20 08:27:04 +09:00
Kenichi Ishigaki
9c1b3501f7 fix the number of tests to skip (fix #44) 2019-01-20 08:23:49 +09:00
Kenichi Ishigaki
4dd0bf8167 no warnings 'locale' 2019-01-18 05:13:34 +09:00
Kenichi Ishigaki
9696efa8bf requires Test::More 0.88 for done_testing 2019-01-07 03:51:01 +09:00
Kenichi Ishigaki
627666e888 not to use Test::FailWarnings except for developers environment 2019-01-07 03:48:10 +09:00
Kenichi Ishigaki
f56689d929 use more test utility functions 2019-01-07 03:41:09 +09:00
Kenichi Ishigaki
cdb721d162 use note to hide debug messages 2019-01-07 03:39:10 +09:00
Kenichi Ishigaki
49ea768740 fixed a broken test because Test::NoWarnings was gone 2019-01-06 22:28:30 +09:00
Kenichi Ishigaki
c17009cea0 updated MANIFEST 2019-01-06 22:27:05 +09:00
Kenichi Ishigaki
fdde5b98ef use Test::FailWarnings as Test::NoWarnings does not play well with done_testing 2019-01-06 09:17:14 +09:00
Kenichi Ishigaki
c84a0a9781 use done_testing and remove plan tests 2019-01-06 09:03:41 +09:00
Kenichi Ishigaki
fc55eeb0d7 fixed mixed EOLs and removed redundant blank lines 2019-01-06 05:55:34 +09:00
Kenichi Ishigaki
11c2f4e70f use warnings 2019-01-02 21:17:30 +09:00
Kenichi Ishigaki
12ab284322 removed shebang from tests 2019-01-02 21:10:51 +09:00
Kenichi Ishigaki
48740e8f30 removed executable bit from a test 2019-01-02 20:55:34 +09:00
Kenichi Ishigaki
81d35f23ba
Merge pull request #42 from fsbruva/master
(Makefile.PL): Correct required version of Test::More
2019-01-02 02:15:39 +09:00
fsbruva@yahoo.com
cd85706b93
(Makefile.PL): Correct required version of Test::More
According to the Perl documentation, the functions note() and
explain() appeared in Test::More version 0.82. Since these functions
are used within the DBD::SQLite tests, the minimum required version
of Test::More needs to be corrected. Without the proper version,
the build fails on Perls earlier than 5.10. For more information:
https://perldoc.perl.org/Test/More.html#COMPATIBILITY
2019-01-01 14:17:31 +00:00
Kenichi Ishigaki
ed267b92cc ignore a few extensions 2018-12-29 03:02:53 +09:00
Kenichi Ishigaki
fb1cf99dde release 1.62 2018-12-29 02:57:17 +09:00
Kenichi Ishigaki
b4a47ef2cf added tests for sqlite_db_config(..., -1) 2018-12-29 02:56:29 +09:00
Kenichi Ishigaki
fc491a64a9 add more examples for sqlite_db_config (wyant++) 2018-12-23 02:13:04 +09:00
Kenichi Ishigaki
2bbdf48fd7 fixed typo (wyant++) 2018-12-23 01:47:50 +09:00
Kenichi Ishigaki
f05eecb56e release 1.61_04 2018-12-22 15:35:12 +09:00
Kenichi Ishigaki
a719c681d4 add sqlite_defensive option 2018-12-22 15:18:41 +09:00
Kenichi Ishigaki
30c290f49f replace a old sample version number with the latest 2018-12-22 05:28:46 +09:00
Kenichi Ishigaki
2c2d9800f3 fixed pod 2018-12-22 05:28:19 +09:00
Kenichi Ishigaki
35e96238b2 s/http/https/g 2018-12-22 05:27:59 +09:00
Kenichi Ishigaki
8bc5cba09d updated %since 2018-12-22 05:26:54 +09:00
Kenichi Ishigaki
d166633c01 ignore missing sqlite tarballs 2018-12-22 05:25:55 +09:00
Kenichi Ishigaki
9c851bf852 warn if versions in %since/%until does not match the known sqlite version numbers 2018-12-22 05:25:19 +09:00
Kenichi Ishigaki
a4126d6742 show also a tag for a changed constant 2018-12-22 05:20:50 +09:00
Kenichi Ishigaki
843ecf112f make ignore check a bit stricter 2018-12-22 05:18:46 +09:00
Kenichi Ishigaki
f16117c342 cleanup $ignore_tag_re and add some explanation to make it easier for me to expose some of the constants that are only ignored because corresponding interfaces are not implemented yet 2018-12-22 05:17:28 +09:00
Kenichi Ishigaki
d6d91ff948 fixed wrong sqlite version numbers 2018-12-22 05:13:18 +09:00
Kenichi Ishigaki
ffe1410978 expose DBCONFIG constants 2018-12-22 05:11:53 +09:00
Kenichi Ishigaki
a28532af37 implemented sqlite_db_config interface (RT-128056) 2018-12-22 05:09:06 +09:00
Kenichi Ishigaki
b8c5535548 release 1.61_03 2018-12-19 22:02:35 +09:00
Kenichi Ishigaki
3a326fea9f updated SQLite to 3.26.0 2018-12-06 01:59:14 +09:00
Kenichi Ishigaki
c02316e38b release 1.61_02 2018-12-01 18:08:01 +09:00
Kenichi Ishigaki
954ab8f289 changed the preferred bugtracker 2018-12-01 18:02:24 +09:00
Kenichi Ishigaki
45f473b587 Merge branch 'backup_between_dbhs' 2018-12-01 17:53:45 +09:00
Kenichi Ishigaki
eb0ca0a851 added a note on sqlite_prefer_numeric_type 2018-12-01 17:53:15 +09:00
Kenichi Ishigaki
61e1616c61 implemented type_info_all 2018-12-01 17:53:14 +09:00
Kenichi Ishigaki
da7f64c53d introduced sqlite_prefer_numeric_type handle attribute 2018-12-01 17:53:14 +09:00
Kenichi Ishigaki
071abbab23 these are not TODO any more 2018-12-01 17:53:14 +09:00
Kenichi Ishigaki
4af5487ca1 removed a type test in rt_40594_nullable.t 2018-12-01 17:53:14 +09:00
Kenichi Ishigaki
7c811dd4f4 TYPE statement attribute should be integer (RT#46873) 2018-12-01 17:53:14 +09:00
Kenichi Ishigaki
67af7629f9 added missing declarations 2018-12-01 17:52:34 +09:00
Kenichi Ishigaki
6faa8a3c90 Implemented backup_to_dbh/backup_from_dbh (#30) 2018-12-01 17:48:46 +09:00
Kenichi Ishigaki
881131445e Merge branch 'type_fix' 2018-12-01 17:43:36 +09:00
Kenichi Ishigaki
1aafac2382 added a note on sqlite_prefer_numeric_type 2018-12-01 17:42:57 +09:00
Kenichi Ishigaki
00dfbbaad6 implemented type_info_all 2018-12-01 17:32:55 +09:00
Kenichi Ishigaki
6a86e54992 introduced sqlite_prefer_numeric_type handle attribute 2018-12-01 17:32:55 +09:00
Kenichi Ishigaki
09288710c5 these are not TODO any more 2018-12-01 17:30:47 +09:00
Kenichi Ishigaki
90cf41a773 removed a type test in rt_40594_nullable.t 2018-12-01 17:30:47 +09:00
Kenichi Ishigaki
f04f766d71 TYPE statement attribute should be integer (RT#46873) 2018-12-01 17:30:47 +09:00
Kenichi Ishigaki
47c115cae2 fix the number of tests for ancient DBI 2018-12-01 17:11:42 +09:00
Kenichi Ishigaki
315b86627d release 1.61_01 2018-12-01 16:58:18 +09:00
Kenichi Ishigaki
7ee8310ae7 fix the number of workarounds 2018-12-01 13:58:07 +09:00
Kenichi Ishigaki
b762aa2ca2 updated README 2018-12-01 13:55:09 +09:00
Kenichi Ishigaki
35f91fe215 replaced a link to search.cpan.org with the equivalent metacpan.org link 2018-12-01 13:53:07 +09:00
Kenichi Ishigaki
a2161f0b93 added .pl to MANIFEST.SKIP 2018-12-01 13:51:00 +09:00
Kenichi Ishigaki
66dff77e10 added sqlite_limit method 2018-12-01 13:50:45 +09:00
Kenichi Ishigaki
b8a821edf6 updated constants 2018-12-01 12:59:25 +09:00
Kenichi Ishigaki
85f80b9e6d made run-time limit constant group public 2018-12-01 12:58:43 +09:00
Kenichi Ishigaki
e28c47f5cf hid some newly added constant groups 2018-12-01 12:57:59 +09:00
Kenichi Ishigaki
3e9195bd53 updated api history 2018-12-01 12:56:19 +09:00
Kenichi Ishigaki
433a971b7e bumped up SQLite to 3.25.3 2018-12-01 11:46:22 +09:00
Kenichi Ishigaki
3efc738102
Merge pull request #39 from kiwiroy/configure-max-length
Add ability to configure SQLITE_MAX_LENGTH with environment variable
2018-12-01 11:43:46 +09:00
Kenichi Ishigaki
7dec2b8c1f release 1.60 2018-12-01 11:42:02 +09:00
Roy Storey
0c702a3488 add ability to configure SQLITE_MAX_LENGTH with environment variable 2018-11-28 11:17:55 +13:00
Kenichi Ishigaki
d116a5228e release 1.59_03 2018-11-03 21:11:48 +09:00
Kenichi Ishigaki
1e2d7839ba updated Changes 2018-11-03 21:10:33 +09:00
Kenichi Ishigaki
1eda646cd8 Apply a patch from Björn Höhrmann (fix #31) 2018-11-03 17:13:55 +09:00
Kenichi Ishigaki
f3b305d442 add a note on TYPE statement handle attribute 2018-11-03 17:00:39 +09:00
Kenichi Ishigaki
817c9a5669 mention cast() function 2018-11-03 16:28:08 +09:00
Kenichi Ishigaki
998847196d use func to support older DBI 2018-10-13 17:48:20 +09:00
Kenichi Ishigaki
198ae95635 release 1.59_02 2018-09-30 15:08:54 +09:00
Kenichi Ishigaki
9fcf565c11 Update SQLite to 3.25.2 2018-09-30 15:06:15 +09:00
Kenichi Ishigaki
d8652e4a66 release 1.59_01 2018-09-17 04:08:57 +09:00
Kenichi Ishigaki
52c2e15fa5 fix a broken virtual filecontent table test 2018-09-17 04:07:42 +09:00
Kenichi Ishigaki
c8ee5f0500 updated MANIFEST 2018-09-17 04:07:06 +09:00
Kenichi Ishigaki
113ca70aa5 Fix to use a PV value as a virtual table column value where appropriate (RT-124941) 2018-09-17 03:46:52 +09:00
Kenichi Ishigaki
8491f808d3 Update SQLite to 3.25.0 2018-09-16 17:42:20 +09:00
Kenichi Ishigaki
8ee8ac791c
Merge pull request #35 from mohawk2/add-deferrability
Add deferrability parsing to foreign_key_info
2018-08-28 02:36:09 +09:00
Ed J
26d25a4edd doc that DEFERRABILITY now handled 2018-08-26 22:42:49 +01:00
Ed J
128d379a0d handle other kinds of deferrable 2018-08-26 22:26:34 +01:00
Ed J
9f54d4eba1 refactor for DRY 2018-08-26 22:17:30 +01:00
Ed J
8500529c1b add deferrability to foreign_key_info 2018-08-26 22:02:12 +01:00
Kenichi Ishigaki
817956ba5b Applied a patch by Bo Lindbergh (RT-125068) 2018-05-01 14:21:17 +09:00
Kenichi Ishigaki
8169fbe7e5 updated Changes 2018-05-01 14:06:46 +09:00
Kenichi Ishigaki
36cb5c9611
Merge pull request #32 from SineSwiper/feature/get_info
Create DBD::SQLite::GetInfo with a more verbose set of data
2018-05-01 14:02:06 +09:00
Brendan Byrd
62a54a4610 Create DBD::SQLite::GetInfo with a more verbose set of data 2018-04-30 19:45:39 -04:00
Kenichi Ishigaki
501f4d6443 Update SQLite to 3.23.0 2018-04-03 00:34:43 +09:00
Kenichi Ishigaki
9ae307d375 releng 1.58 2018-03-28 20:54:53 +09:00
Kenichi Ishigaki
a78838dcf8 releng 1.57_01 2018-03-21 15:43:19 +09:00
Kenichi Ishigaki
1d665d8661 fetching attributes from a statement handle whose database handle is disabled should return an error, instead of coredump under perl with -fsanitize=address
- reported by Peter Rabbitson
2018-03-21 15:04:09 +09:00
147 changed files with 95257 additions and 39250 deletions

35
.github/workflows/build.yml vendored Normal file
View file

@ -0,0 +1,35 @@
name: build
on:
push:
branches:
- '*'
tags-ignore:
- '*'
pull_request:
jobs:
perl:
runs-on: ubuntu-latest
strategy:
matrix:
perl-version:
- '5.8-buster'
- '5.10-buster'
- '5.18-buster'
- '5.20-buster'
- '5.26'
- 'latest'
container:
image: perl:${{ matrix.perl-version }}
steps:
- uses: actions/checkout@v4
- name: perl -V
run: perl -V
- name: Install dependencies
run: curl -sL https://git.io/cpm | perl - install -g --with-recommends --with-test --with-configure --show-build-log-on-failure
- name: Run tests
run: perl Makefile.PL && make && make test

24
.github/workflows/build_mac.yml vendored Normal file
View file

@ -0,0 +1,24 @@
name: build_mac
on:
push:
branches:
- '*'
tags-ignore:
- '*'
pull_request:
jobs:
perl:
runs-on: macOS-latest
steps:
- uses: actions/checkout@master
- name: perl -V
run: perl -V
- name: Install dependencies with develop
run: curl -sL https://git.io/cpm | perl - install -g --with-recommends --with-test --with-configure --with-develop --show-build-log-on-failure
- name: Run Makefile.PL
run: perl Makefile.PL
- name: Run tests
run: make && make test

28
.github/workflows/build_windows.yml vendored Normal file
View file

@ -0,0 +1,28 @@
name: build_windows
on:
push:
branches:
- '*'
tags-ignore:
- '*'
pull_request:
jobs:
perl:
runs-on: windows-latest
steps:
- uses: actions/checkout@master
# - name: Set up Perl
# run: |
# choco install strawberryperl
# echo "##[add-path]C:\strawberry\c\bin;C:\strawberry\perl\site\bin;C:\strawberry\perl\bin"
- name: perl -V
run: perl -V
- name: Install dependencies with develop
run: curl -sL https://git.io/cpm | perl - install -g --with-recommends --with-test --with-configure --with-develop --show-build-log-on-failure
- name: Run Makefile.PL
run: perl Makefile.PL
- name: Run tests
run: gmake test

3
.gitignore vendored
View file

@ -18,3 +18,6 @@ foo*
tmp/
*.pl
*.old
*.bak
*.sqlite
.perl-version

View file

@ -1,3 +1,4 @@
dist: trusty
language: perl
perl:
# - "5.8.1"

198
Changes
View file

@ -1,5 +1,203 @@
Changes for Perl extension DBD-SQLite
1.76 2024-10-19
- Switched to a production version
1.75_01 2024-09-17
- Upgraded SQLite to 3.46.1
- Fix for Windows quadmath builds (GH#115, sisyphus++)
- Omit load_extension if static build
1.74 2023-09-20
- Switched to a production version
1.73_01 2023-07-09
- Upgraded SQLite to 3.42.0
- Add missing possible table_type values to POD (GH#105, dboehmer++)
1.72 2022-11-04
- Switched to a production version
1.71_07 2022-10-26
- Upgraded SQLite to 3.39.4
1.71_06 2022-03-12
- Set UTF8CACHE to avoid slowdown with -DDEBUGGING (andk, Leont, FGasper)
1.71_05 2022-02-26
- Fix another test failure on perl built with -DDEBUGGING
- Lowercase datatype in table column metadata for backcompat
1.71_04 2022-02-26
- Fix test failure on perl built with -DDEBUGGING (andk++)
1.71_03 2022-02-23
- Upgraded SQLite to 3.38.0
- Expose sqlite_error_offset introduced in 3.38.0
1.71_02 2022-01-07
- Upgraded SQLite to 3.37.2
- Improve sqlite_load_extension doc (GH#94, Derek Lamb++)
1.71_01 2021-12-02
- Upgraded SQLite to 3.37.0
- Add a feature to unregister a created function
- Fix accented characters in POD (GH#90, HaraldJoerg++)
1.70 2021-08-01
- Switched to a production version
1.69_02 2021-07-30
- Fix doc to use the correct attribute with sqlite_ (GH#86, eekboek++)
- Modify the fix to silence the sqlite_unicode warning not to check
the attribute twice
- Fix an encoding issue of naive (GH#83, HaraldJoerg++)
1.69_01 2021-07-30
- Typo (GH#85, grr++)
- Silenced deprecation warning of sqlite_unicode not to break
tests of existing applications
1.68 2021-07-22
- Switched to a production version
1.67_07 2021-06-19
- Upgraded SQLite to 3.36.0
1.67_06 2021-06-14
- Experiment with another quadmath patch to see if it works
with an older version of FreeBSD
1.67_05 2021-06-13
- Made DBD_SQLITE_STRING_MODE constants exportable
1.67_04 2021-05-31
- Upgraded SQLite to 3.35.5
- Stop setting THREADSAFE=0 if perl has pthread (ie. 5.20+)
(Bjoern Hoehrmann++, GH#69, #72)
- Fixed a memory leak in ::VirtualTable
- Introduced "string_mode" handle attribute (Felipe Gasper++)
to fix long-standing issues of sqlite_unicode (GH#78, #68)
- Added a dependency from dbdimp.o to the *.inc files included
into dbdimp.c (Laurent Dami++, GH#74)
- Fixed an offset issue of VirtualTable (Laurent Dami++, GH#75)
1.67_03 2021-03-31
- Upgraded SQLite to 3.35.3
- Enabled math functions introduced in SQLite 3.35
- Fix quadmath issues (Tux++, leont++)
1.67_02 2020-12-06
- Upgraded SQLite to 3.34.0
- Added a few new constants
- Added sqlite_txn_state method to see internal state
of the backend
1.67_01 2020-11-24
- Switched to XSLoader (GH#63; toddr++)
- Use quadmath_snprintf if USE_QUADMATH is defined
- Use av_fetch instead of av_shift (norimy++)
1.66 2020-08-30
- Switched to a production version
1.65_03 2020-07-27
- Upgraded SQLite to 3.32.3
1.65_02 2020-02-08
- Upgraded SQLite to 3.31.1
1.65_01 2020-01-18
- Upgraded SQLite to 3.30.1
- Added several SQL_ types as alias (pali++)
- Fixed two initialization issues (ppisar++)
- Allowed create_function to return an array reference
to specify the type of the value
1.64 2019-08-12
- Switched to a production version
1.63_05 2019-07-12
- Upgraded SQLite to 3.29.0
- Added sqlite_get_autocommit private method (GH#52)
- Addded new db_config constants, notably to prohibit
double-quoted string literals
1.63_04 2019-05-25
- Upgraded SQLite to 3.28.0
- Modified doc for sqlite_db_filename which actually returns undef
or an empty string (GH#50)
- Fixed ->quote($blob, SQL_BLOB) to quote correctly (GH#51, pali++)
1.63_03 2019-02-15
- Applied a patch to fix segmentation fault on 32-bit big-endian
platforms by Niko Tyni (GH#45)
1.63_02 2019-02-14
- Upgraded SQLite to 3.27.1
- Let a URI filename test skip if SQLite is compiled with URI filename
support (GH#47)
1.63_01 2019-01-26
- Made sure an internal hv is initialized (GH#45)
- Fixed a number of tests to skip
- Bumped up Test::More requirement
- Replaced bundled Test::NoWarnings with Test::FailWarnings
- Handle 'unknown' op in DBD::SQLite::VirtualTable::PerlData (Corion++)
1.62 2018-12-29
- Switched to a production version
1.61_04 2018-12-22
- Added sqlite_db_config method and new constants for it
- Added sqlite_defensive option to disallow dangerous SQLite features
- Exposed some of the hidden extended result codes
1.61_03 2018-12-19
- Upgraded SQLite to 3.26.0, which reportedly has a security fix
1.61_02 2018-12-01
- Added sqlite_backup_from_dbh/sqlite_backup_to_dbh methods
- Introduced sqlite_prefer_numeric_type database handle attribute
that changes the value of TYPE statement handle attribute
from an array of string to an array of integer, as an experimental
feature. Setting this may break your applications.
- Changed preferred bugtracker
1.61_01 2018-12-01
- Added ability to configure SQLITE_MAX_LENGT with environmental
variable (Roy Storey)
- Added sqlite_limit database handle method to change run-time limits
- Upgraded SQLite to 3.25.3
- Updated constants
1.60 2018-12-01
- Switched to a production version
1.59_03 2018-11-03
- Added a note on the long standing bug on TYPE statement
handle attribute
- Applied a doc patch on Virtual::PerlData by Björn Höhrmann
(GH-31)
1.59_02 2018-09-30
- Upgraded SQLite to 3.25.2
1.59_01 2018-09-17
- Upgraded SQLite to 3.25.0, with ALTER TABLE ... RENAME COLUMN
and UPSERT among others
- Added ::GetInfo (GH#32, Brendan Byrd)
- Fix to use a PV value as a virtual table column value
where appropriate (RT-124941)
- Add deferrability to foreign_key_info (mohawk2)
1.58 2018-03-28
- Switched to a production version.
1.57_01 2018-03-21
- Made it an error to fetch attributes from a statement
handle whose database handle is inactive (ribasushi++)
1.56 2018-02-28
- Switched to a production version.

View file

@ -6,12 +6,12 @@ dbdimp.h
dbdimp_tokenizer.inc
dbdimp_virtual_table.inc
fts3_tokenizer.h
inc/Test/NoWarnings.pm
inc/Test/NoWarnings/Warning.pm
inc/Test/FailWarnings.pm
lib/DBD/SQLite.pm
lib/DBD/SQLite/Constants.pm
lib/DBD/SQLite/Cookbook.pod
lib/DBD/SQLite/Fulltext_search.pod
lib/DBD/SQLite/GetInfo.pm
lib/DBD/SQLite/VirtualTable.pm
lib/DBD/SQLite/VirtualTable/FileContent.pm
lib/DBD/SQLite/VirtualTable/PerlData.pm
@ -36,6 +36,7 @@ t/07_error.t
t/08_busy.t
t/09_create_function.t
t/10_create_aggregate.t
t/11_get_info.t
t/12_unicode.t
t/13_create_collation.t
t/14_progress_handler.t
@ -87,6 +88,9 @@ t/60_readonly.t
t/61_strlike.t
t/62_regexp_multibyte_char_class.t
t/63_param_values.t
t/64_limit.t
t/65_db_config.t
t/66_get_autocommit.t
t/cookbook_variance.t
t/lib/SQLiteTest.pm
t/rt_106151_outermost_savepoint.t
@ -133,7 +137,9 @@ t/virtual_table/10_filecontent.t
t/virtual_table/11_filecontent_fulltext.t
t/virtual_table/20_perldata.t
t/virtual_table/21_perldata_charinfo.t
t/virtual_table/rt_124941.t
t/virtual_table/rt_99748.t
t/virtual_table/unknown_op.t
typemap
xt/cpp_comments.t
xt/meta.t

View file

@ -12,6 +12,7 @@ CVS/.*
\.xsi$
\.bs$
\.el$
\.pl$
^.#
^mess/
^sqlite/

View file

@ -236,6 +236,7 @@ my @CC_DEFINE = (
# '-DSQLITE_ENABLE_STAT4', # for sqlite >= 3.8.3.1
'-DSQLITE_ENABLE_JSON1', # for sqlite >= 3.9.0
'-DSQLITE_ENABLE_FTS5', # for sqlite >= 3.9.0
'-DSQLITE_ENABLE_MATH_FUNCTIONS', # for sqlite >= 3.35.0
'-DNDEBUG=1',
);
@ -244,6 +245,11 @@ if ($ENV{SQLITE_ENABLE_FTS3_TOKENIZER}) {
push @CC_DEFINE, '-DSQLITE_ENABLE_FTS3_TOKENIZER'; # for sqlite >= 3.11.0
}
if ($ENV{SQLITE_MAX_LENGTH} && $ENV{SQLITE_MAX_LENGTH} =~ m/^[0-9]+$/) {
push @CC_DEFINE, join '=', '-DSQLITE_MAX_LENGTH', $ENV{SQLITE_MAX_LENGTH}
if $ENV{SQLITE_MAX_LENGTH} >= 100 && $ENV{SQLITE_MAX_LENGTH} <= ((2**31)-1);
}
if (DEVELOPER_ONLY) {
# for sqlite >= 3.8.8
push @CC_DEFINE, '-DSQLITE_ENABLE_API_ARMOR';
@ -256,7 +262,7 @@ if ( $^O eq 'cygwin') {
if ( $Config{d_usleep} || $Config{osname} =~ m/linux/ ) {
push @CC_DEFINE, '-DHAVE_USLEEP=1';
}
unless ( $Config{usethreads} ) {
if ( !$Config{usethreads} and $Config{libs} !~ /pthread/ ) {
push @CC_DEFINE, '-DTHREADSAFE=0';
}
if ($^O eq 'hpux' and $Config{osvers} <= 10.20) {
@ -282,8 +288,18 @@ if ($^O =~ /bsd/i && $^O !~ /(?:open|net)bsd/) {
push @CC_DEFINE, '-D_XOPEN_SOURCE';
}
if (!$Config{usedl}) {
push @CC_DEFINE, '-DSQLITE_OMIT_LOAD_EXTENSION';
}
my (@CCFLAGS, @LDFLAGS, @LDDLFLAGS);
if ($ENV{TEST_DBD_SQLITE_WITH_ASAN}) {
push @CCFLAGS, '-fsanitize=address -static-libasan -fuse-ld=gold -fno-omit-frame-pointer -g -O2';
push @LDFLAGS, '-fsanitize=address -static-libasan -fuse-ld=gold -fno-omit-frame-pointer -g -O2';
push @LDDLFLAGS, '-fsanitize=address -static-libasan -fuse-ld=gold -fno-omit-frame-pointer -g -O2';
}
# RT #70135: See if ld supports Bsymbolic;
unless ($^O eq 'MSWin32' && $Config{ld} =~ /link/) {
for my $path (File::Spec->path) {
@ -330,8 +346,7 @@ WriteMakefile(
'Tie::Hash' => 0,
'File::Spec' => (WINLIKE ? '3.27' : '0.82'),
'DBI' => $DBI_required,
'Test::More' => '0.47', # Test::NoWarnings
'Test::Builder' => '0.86', # Test::NoWarnings
'Test::More' => '0.88', # done_testing
( WINLIKE ? (
'Win32' => '0.30',
) : () ),
@ -362,9 +377,7 @@ WriteMakefile(
},
build_requires => {
'File::Spec' => (WINLIKE ? '3.27' : '0.82'),
'Test::More' => '0.42',
# Bundled in /inc
# 'Test::NoWarnings' => '0.081',
'Test::More' => '0.88',
},
requires => {
'Tie::Hash' => 0,
@ -376,7 +389,7 @@ WriteMakefile(
},
resources => {
license => 'http://dev.perl.org/licenses/',
bugtracker => 'http://rt.cpan.org/Public/Dist/Display.html?Name=DBD-SQLite',
bugtracker => 'https://github.com/DBD-SQLite/DBD-SQLite/issues',
repository => 'https://github.com/DBD-SQLite/DBD-SQLite',
MailingList => 'http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbd-sqlite',
},
@ -391,11 +404,14 @@ WriteMakefile(
? '$(O_FILES)'
: 'SQLite.o dbdimp.o'
),
depend => {
'dbdimp.o' => 'dbdimp_tokenizer.inc dbdimp_virtual_table.inc',
},
clean => {
FILES => 'SQLite.xsi config.h tv.log *.old',
},
test => {
TESTS => 't/*.t t/**/*.t',
TESTS => 't/*.t t/*/*.t',
},
PL_FILES => {},
EXE_FILES => [],

1424
README

File diff suppressed because it is too large Load diff

View file

@ -259,6 +259,28 @@ backup_to_file(dbh, filename)
OUTPUT:
RETVAL
static int
backup_from_dbh(dbh, from)
SV *dbh
SV *from
ALIAS:
DBD::SQLite::db::sqlite_backup_from_dbh = 1
CODE:
RETVAL = sqlite_db_backup_from_dbh(aTHX_ dbh, from);
OUTPUT:
RETVAL
static int
backup_to_dbh(dbh, to)
SV *dbh
SV *to
ALIAS:
DBD::SQLite::db::sqlite_backup_to_dbh = 1
CODE:
RETVAL = sqlite_db_backup_to_dbh(aTHX_ dbh, to);
OUTPUT:
RETVAL
HV*
table_column_metadata(dbh, dbname, tablename, columnname)
SV* dbh
@ -318,6 +340,74 @@ create_module(dbh, name, perl_class)
OUTPUT:
RETVAL
static int
limit(dbh, id, new_value = -1)
SV *dbh
int id
int new_value
ALIAS:
DBD::SQLite::db::sqlite_limit = 1
CODE:
{
RETVAL = sqlite_db_limit(aTHX_ dbh, id, new_value);
}
OUTPUT:
RETVAL
static int
db_config(dbh, id, new_value = -1)
SV *dbh
int id
int new_value
ALIAS:
DBD::SQLite::db::sqlite_db_config = 1
CODE:
{
RETVAL = sqlite_db_config(aTHX_ dbh, id, new_value);
}
OUTPUT:
RETVAL
static int
get_autocommit(dbh)
SV *dbh
ALIAS:
DBD::SQLite::db::sqlite_get_autocommit = 1
CODE:
{
RETVAL = sqlite_db_get_autocommit(aTHX_ dbh);
}
OUTPUT:
RETVAL
static int
txn_state(SV* dbh, SV *schema = &PL_sv_undef)
ALIAS:
DBD::SQLite::db::sqlite_txn_state = 1
CODE:
{
RETVAL = sqlite_db_txn_state(aTHX_ dbh, schema);
}
OUTPUT:
RETVAL
static int
error_offset(dbh)
SV *dbh
ALIAS:
DBD::SQLite::db::sqlite_error_offset = 1
CODE:
{
#if SQLITE_VERSION_NUMBER >= 3038000
D_imp_dbh(dbh);
RETVAL = sqlite3_error_offset(imp_dbh->db);
#else
RETVAL = -1;
#endif
}
OUTPUT:
RETVAL
MODULE = DBD::SQLite PACKAGE = DBD::SQLite::st

View file

@ -5,6 +5,41 @@ MODULE = DBD::SQLite PACKAGE = DBD::SQLite::Constants
PROTOTYPES: ENABLE
BOOT:
newCONSTSUB( gv_stashpv("DBD::SQLite::Constants", FALSE), "DBD_SQLITE_STRING_MODE_PV", newSVuv(DBD_SQLITE_STRING_MODE_PV) );
newCONSTSUB( gv_stashpv("DBD::SQLite::Constants", FALSE), "DBD_SQLITE_STRING_MODE_BYTES", newSVuv(DBD_SQLITE_STRING_MODE_BYTES) );
newCONSTSUB( gv_stashpv("DBD::SQLite::Constants", FALSE), "DBD_SQLITE_STRING_MODE_UNICODE_NAIVE", newSVuv(DBD_SQLITE_STRING_MODE_UNICODE_NAIVE) );
newCONSTSUB( gv_stashpv("DBD::SQLite::Constants", FALSE), "DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK", newSVuv(DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK) );
newCONSTSUB( gv_stashpv("DBD::SQLite::Constants", FALSE), "DBD_SQLITE_STRING_MODE_UNICODE_STRICT", newSVuv(DBD_SQLITE_STRING_MODE_UNICODE_STRICT) );
#if SQLITE_VERSION_NUMBER >= 3034000
IV
_const_allowed_return_values_from_sqlite3_txn_state_3034000()
ALIAS:
SQLITE_TXN_NONE = SQLITE_TXN_NONE
SQLITE_TXN_READ = SQLITE_TXN_READ
SQLITE_TXN_WRITE = SQLITE_TXN_WRITE
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_allowed_return_values_from_sqlite3_txn_state_3034000_zero()
ALIAS:
SQLITE_TXN_NONE = 1
SQLITE_TXN_READ = 2
SQLITE_TXN_WRITE = 3
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
IV
_const_authorizer_action_codes()
ALIAS:
@ -112,6 +147,378 @@ _const_compile_time_library_version_numbers()
OUTPUT:
RETVAL
#if SQLITE_VERSION_NUMBER >= 3007000
IV
_const_database_connection_configuration_options_3007000()
ALIAS:
SQLITE_DBCONFIG_LOOKASIDE = SQLITE_DBCONFIG_LOOKASIDE
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3007000_zero()
ALIAS:
SQLITE_DBCONFIG_LOOKASIDE = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3007006
IV
_const_database_connection_configuration_options_3007006()
ALIAS:
SQLITE_DBCONFIG_ENABLE_FKEY = SQLITE_DBCONFIG_ENABLE_FKEY
SQLITE_DBCONFIG_ENABLE_TRIGGER = SQLITE_DBCONFIG_ENABLE_TRIGGER
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3007006_zero()
ALIAS:
SQLITE_DBCONFIG_ENABLE_FKEY = 1
SQLITE_DBCONFIG_ENABLE_TRIGGER = 2
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3012002
IV
_const_database_connection_configuration_options_3012002()
ALIAS:
SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER = SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3012002_zero()
ALIAS:
SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3013000
IV
_const_database_connection_configuration_options_3013000()
ALIAS:
SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3013000_zero()
ALIAS:
SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3015000
IV
_const_database_connection_configuration_options_3015000()
ALIAS:
SQLITE_DBCONFIG_MAINDBNAME = SQLITE_DBCONFIG_MAINDBNAME
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3015000_zero()
ALIAS:
SQLITE_DBCONFIG_MAINDBNAME = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3016000
IV
_const_database_connection_configuration_options_3016000()
ALIAS:
SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE = SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3016000_zero()
ALIAS:
SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3020000
IV
_const_database_connection_configuration_options_3020000()
ALIAS:
SQLITE_DBCONFIG_ENABLE_QPSG = SQLITE_DBCONFIG_ENABLE_QPSG
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3020000_zero()
ALIAS:
SQLITE_DBCONFIG_ENABLE_QPSG = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3022000
IV
_const_database_connection_configuration_options_3022000()
ALIAS:
SQLITE_DBCONFIG_TRIGGER_EQP = SQLITE_DBCONFIG_TRIGGER_EQP
SQLITE_DBCONFIG_MAX = SQLITE_DBCONFIG_MAX
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3022000_zero()
ALIAS:
SQLITE_DBCONFIG_TRIGGER_EQP = 1
SQLITE_DBCONFIG_MAX = 2
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3024000
IV
_const_database_connection_configuration_options_3024000()
ALIAS:
SQLITE_DBCONFIG_RESET_DATABASE = SQLITE_DBCONFIG_RESET_DATABASE
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3024000_zero()
ALIAS:
SQLITE_DBCONFIG_RESET_DATABASE = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3026000
IV
_const_database_connection_configuration_options_3026000()
ALIAS:
SQLITE_DBCONFIG_DEFENSIVE = SQLITE_DBCONFIG_DEFENSIVE
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3026000_zero()
ALIAS:
SQLITE_DBCONFIG_DEFENSIVE = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3028000
IV
_const_database_connection_configuration_options_3028000()
ALIAS:
SQLITE_DBCONFIG_WRITABLE_SCHEMA = SQLITE_DBCONFIG_WRITABLE_SCHEMA
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3028000_zero()
ALIAS:
SQLITE_DBCONFIG_WRITABLE_SCHEMA = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3029000
IV
_const_database_connection_configuration_options_3029000()
ALIAS:
SQLITE_DBCONFIG_LEGACY_ALTER_TABLE = SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
SQLITE_DBCONFIG_DQS_DML = SQLITE_DBCONFIG_DQS_DML
SQLITE_DBCONFIG_DQS_DDL = SQLITE_DBCONFIG_DQS_DDL
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3029000_zero()
ALIAS:
SQLITE_DBCONFIG_LEGACY_ALTER_TABLE = 1
SQLITE_DBCONFIG_DQS_DML = 2
SQLITE_DBCONFIG_DQS_DDL = 3
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3030000
IV
_const_database_connection_configuration_options_3030000()
ALIAS:
SQLITE_DBCONFIG_ENABLE_VIEW = SQLITE_DBCONFIG_ENABLE_VIEW
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3030000_zero()
ALIAS:
SQLITE_DBCONFIG_ENABLE_VIEW = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3031000
IV
_const_database_connection_configuration_options_3031000()
ALIAS:
SQLITE_DBCONFIG_LEGACY_FILE_FORMAT = SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
SQLITE_DBCONFIG_TRUSTED_SCHEMA = SQLITE_DBCONFIG_TRUSTED_SCHEMA
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3031000_zero()
ALIAS:
SQLITE_DBCONFIG_LEGACY_FILE_FORMAT = 1
SQLITE_DBCONFIG_TRUSTED_SCHEMA = 2
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3042000
IV
_const_database_connection_configuration_options_3042000()
ALIAS:
SQLITE_DBCONFIG_STMT_SCANSTATUS = SQLITE_DBCONFIG_STMT_SCANSTATUS
SQLITE_DBCONFIG_REVERSE_SCANORDER = SQLITE_DBCONFIG_REVERSE_SCANORDER
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_database_connection_configuration_options_3042000_zero()
ALIAS:
SQLITE_DBCONFIG_STMT_SCANSTATUS = 1
SQLITE_DBCONFIG_REVERSE_SCANORDER = 2
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3006002
IV
@ -646,6 +1053,240 @@ _const_extended_result_codes_3021000_zero()
#endif
#if SQLITE_VERSION_NUMBER >= 3022000
IV
_const_extended_result_codes_3022000()
ALIAS:
SQLITE_ERROR_MISSING_COLLSEQ = SQLITE_ERROR_MISSING_COLLSEQ
SQLITE_ERROR_RETRY = SQLITE_ERROR_RETRY
SQLITE_READONLY_CANTINIT = SQLITE_READONLY_CANTINIT
SQLITE_READONLY_DIRECTORY = SQLITE_READONLY_DIRECTORY
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_extended_result_codes_3022000_zero()
ALIAS:
SQLITE_ERROR_MISSING_COLLSEQ = 1
SQLITE_ERROR_RETRY = 2
SQLITE_READONLY_CANTINIT = 3
SQLITE_READONLY_DIRECTORY = 4
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3024000
IV
_const_extended_result_codes_3024000()
ALIAS:
SQLITE_LOCKED_VTAB = SQLITE_LOCKED_VTAB
SQLITE_CORRUPT_SEQUENCE = SQLITE_CORRUPT_SEQUENCE
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_extended_result_codes_3024000_zero()
ALIAS:
SQLITE_LOCKED_VTAB = 1
SQLITE_CORRUPT_SEQUENCE = 2
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3025000
IV
_const_extended_result_codes_3025000()
ALIAS:
SQLITE_ERROR_SNAPSHOT = SQLITE_ERROR_SNAPSHOT
SQLITE_CANTOPEN_DIRTYWAL = SQLITE_CANTOPEN_DIRTYWAL
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_extended_result_codes_3025000_zero()
ALIAS:
SQLITE_ERROR_SNAPSHOT = 1
SQLITE_CANTOPEN_DIRTYWAL = 2
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3031000
IV
_const_extended_result_codes_3031000()
ALIAS:
SQLITE_CANTOPEN_SYMLINK = SQLITE_CANTOPEN_SYMLINK
SQLITE_CONSTRAINT_PINNED = SQLITE_CONSTRAINT_PINNED
SQLITE_OK_SYMLINK = SQLITE_OK_SYMLINK
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_extended_result_codes_3031000_zero()
ALIAS:
SQLITE_CANTOPEN_SYMLINK = 1
SQLITE_CONSTRAINT_PINNED = 2
SQLITE_OK_SYMLINK = 3
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3032000
IV
_const_extended_result_codes_3032000()
ALIAS:
SQLITE_IOERR_DATA = SQLITE_IOERR_DATA
SQLITE_BUSY_TIMEOUT = SQLITE_BUSY_TIMEOUT
SQLITE_CORRUPT_INDEX = SQLITE_CORRUPT_INDEX
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_extended_result_codes_3032000_zero()
ALIAS:
SQLITE_IOERR_DATA = 1
SQLITE_BUSY_TIMEOUT = 2
SQLITE_CORRUPT_INDEX = 3
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3034000
IV
_const_extended_result_codes_3034000()
ALIAS:
SQLITE_IOERR_CORRUPTFS = SQLITE_IOERR_CORRUPTFS
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_extended_result_codes_3034000_zero()
ALIAS:
SQLITE_IOERR_CORRUPTFS = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3037000
IV
_const_extended_result_codes_3037000()
ALIAS:
SQLITE_CONSTRAINT_DATATYPE = SQLITE_CONSTRAINT_DATATYPE
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_extended_result_codes_3037000_zero()
ALIAS:
SQLITE_CONSTRAINT_DATATYPE = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3041000
IV
_const_extended_result_codes_3041000()
ALIAS:
SQLITE_NOTICE_RBU = SQLITE_NOTICE_RBU
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_extended_result_codes_3041000_zero()
ALIAS:
SQLITE_NOTICE_RBU = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3043000
IV
_const_extended_result_codes_3043000()
ALIAS:
SQLITE_IOERR_IN_PAGE = SQLITE_IOERR_IN_PAGE
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_extended_result_codes_3043000_zero()
ALIAS:
SQLITE_IOERR_IN_PAGE = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
IV
_const_flags_for_file_open_operations()
ALIAS:
@ -756,6 +1397,78 @@ _const_flags_for_file_open_operations_3007013_zero()
#endif
#if SQLITE_VERSION_NUMBER >= 3031000
IV
_const_flags_for_file_open_operations_3031000()
ALIAS:
SQLITE_OPEN_NOFOLLOW = SQLITE_OPEN_NOFOLLOW
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_flags_for_file_open_operations_3031000_zero()
ALIAS:
SQLITE_OPEN_NOFOLLOW = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3033000
IV
_const_flags_for_file_open_operations_3033000()
ALIAS:
SQLITE_OPEN_SUPER_JOURNAL = SQLITE_OPEN_SUPER_JOURNAL
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_flags_for_file_open_operations_3033000_zero()
ALIAS:
SQLITE_OPEN_SUPER_JOURNAL = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3037000
IV
_const_flags_for_file_open_operations_3037000()
ALIAS:
SQLITE_OPEN_EXRESCODE = SQLITE_OPEN_EXRESCODE
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_flags_for_file_open_operations_3037000_zero()
ALIAS:
SQLITE_OPEN_EXRESCODE = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3008003
IV
@ -780,6 +1493,80 @@ _const_function_flags_3008003_zero()
#endif
#if SQLITE_VERSION_NUMBER >= 3030000
IV
_const_function_flags_3030000()
ALIAS:
SQLITE_DIRECTONLY = SQLITE_DIRECTONLY
SQLITE_SUBTYPE = SQLITE_SUBTYPE
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_function_flags_3030000_zero()
ALIAS:
SQLITE_DIRECTONLY = 1
SQLITE_SUBTYPE = 2
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3031000
IV
_const_function_flags_3031000()
ALIAS:
SQLITE_INNOCUOUS = SQLITE_INNOCUOUS
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_function_flags_3031000_zero()
ALIAS:
SQLITE_INNOCUOUS = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3044001
IV
_const_function_flags_3044001()
ALIAS:
SQLITE_RESULT_SUBTYPE = SQLITE_RESULT_SUBTYPE
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_function_flags_3044001_zero()
ALIAS:
SQLITE_RESULT_SUBTYPE = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
IV
_const_fundamental_datatypes()
ALIAS:
@ -787,6 +1574,7 @@ _const_fundamental_datatypes()
SQLITE_FLOAT = SQLITE_FLOAT
SQLITE_BLOB = SQLITE_BLOB
SQLITE_NULL = SQLITE_NULL
SQLITE_TEXT = SQLITE_TEXT
CODE:
RETVAL = ix;
OUTPUT:
@ -855,6 +1643,72 @@ _const_result_codes_3007017_zero()
#endif
IV
_const_run_time_limit_categories()
ALIAS:
SQLITE_LIMIT_LENGTH = SQLITE_LIMIT_LENGTH
SQLITE_LIMIT_SQL_LENGTH = SQLITE_LIMIT_SQL_LENGTH
SQLITE_LIMIT_COLUMN = SQLITE_LIMIT_COLUMN
SQLITE_LIMIT_EXPR_DEPTH = SQLITE_LIMIT_EXPR_DEPTH
SQLITE_LIMIT_COMPOUND_SELECT = SQLITE_LIMIT_COMPOUND_SELECT
SQLITE_LIMIT_VDBE_OP = SQLITE_LIMIT_VDBE_OP
SQLITE_LIMIT_FUNCTION_ARG = SQLITE_LIMIT_FUNCTION_ARG
SQLITE_LIMIT_ATTACHED = SQLITE_LIMIT_ATTACHED
SQLITE_LIMIT_LIKE_PATTERN_LENGTH = SQLITE_LIMIT_LIKE_PATTERN_LENGTH
SQLITE_LIMIT_VARIABLE_NUMBER = SQLITE_LIMIT_VARIABLE_NUMBER
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#if SQLITE_VERSION_NUMBER >= 3006018
IV
_const_run_time_limit_categories_3006018()
ALIAS:
SQLITE_LIMIT_TRIGGER_DEPTH = SQLITE_LIMIT_TRIGGER_DEPTH
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_run_time_limit_categories_3006018_zero()
ALIAS:
SQLITE_LIMIT_TRIGGER_DEPTH = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3008007
IV
_const_run_time_limit_categories_3008007()
ALIAS:
SQLITE_LIMIT_WORKER_THREADS = SQLITE_LIMIT_WORKER_THREADS
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const_run_time_limit_categories_3008007_zero()
ALIAS:
SQLITE_LIMIT_WORKER_THREADS = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
# For backward compatibility
MODULE = DBD::SQLite PACKAGE = DBD::SQLite
@ -1070,3 +1924,75 @@ _const__flags_for_file_open_operations_3007013_zero()
#endif
#if SQLITE_VERSION_NUMBER >= 3031000
IV
_const__flags_for_file_open_operations_3031000()
ALIAS:
OPEN_NOFOLLOW = SQLITE_OPEN_NOFOLLOW
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const__flags_for_file_open_operations_3031000_zero()
ALIAS:
OPEN_NOFOLLOW = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3033000
IV
_const__flags_for_file_open_operations_3033000()
ALIAS:
OPEN_SUPER_JOURNAL = SQLITE_OPEN_SUPER_JOURNAL
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const__flags_for_file_open_operations_3033000_zero()
ALIAS:
OPEN_SUPER_JOURNAL = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif
#if SQLITE_VERSION_NUMBER >= 3037000
IV
_const__flags_for_file_open_operations_3037000()
ALIAS:
OPEN_EXRESCODE = SQLITE_OPEN_EXRESCODE
CODE:
RETVAL = ix;
OUTPUT:
RETVAL
#else
IV
_const__flags_for_file_open_operations_3037000_zero()
ALIAS:
OPEN_EXRESCODE = 1
CODE:
RETVAL = 0;
OUTPUT:
RETVAL
#endif

5
cpanfile Normal file
View file

@ -0,0 +1,5 @@
requires 'DBI', '1.57';
on test => sub {
requires 'Test::More', '0.88';
};

561
dbdimp.c
View file

@ -214,6 +214,7 @@ sqlite_type_from_odbc_type(int type)
switch(type) {
case SQL_UNKNOWN_TYPE:
return SQLITE_NULL;
case SQL_BOOLEAN:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
@ -223,7 +224,11 @@ sqlite_type_from_odbc_type(int type)
case SQL_REAL:
case SQL_DOUBLE:
return SQLITE_FLOAT;
case SQL_BIT:
case SQL_BLOB:
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
return SQLITE_BLOB;
default:
return SQLITE_TEXT;
@ -234,11 +239,11 @@ void
init_cxt() {
dTHX;
MY_CXT_INIT;
MY_CXT.last_dbh_is_unicode = 0;
MY_CXT.last_dbh_string_mode = DBD_SQLITE_STRING_MODE_PV;
}
SV *
stacked_sv_from_sqlite3_value(pTHX_ sqlite3_value *value, int is_unicode)
stacked_sv_from_sqlite3_value(pTHX_ sqlite3_value *value, dbd_sqlite_string_mode_t string_mode)
{
STRLEN len;
sqlite_int64 iv;
@ -266,9 +271,7 @@ stacked_sv_from_sqlite3_value(pTHX_ sqlite3_value *value, int is_unicode)
case SQLITE_TEXT:
len = sqlite3_value_bytes(value);
sv = newSVpvn((const char *)sqlite3_value_text(value), len);
if (is_unicode) {
SvUTF8_on(sv);
}
DBD_SQLITE_UTF8_DECODE_IF_NEEDED(sv, string_mode);
return sv_2mortal(sv);
case SQLITE_BLOB:
len = sqlite3_value_bytes(value);
@ -289,6 +292,9 @@ sqlite_set_result(pTHX_ sqlite3_context *context, SV *result, int is_error)
STRLEN len;
char *s;
sqlite3_int64 iv;
AV *av;
SV *result2, *type;
SV **presult2, **ptype;
if ( is_error ) {
s = SvPV(result, len);
@ -299,6 +305,33 @@ sqlite_set_result(pTHX_ sqlite3_context *context, SV *result, int is_error)
/* warn("result: %s\n", SvPV_nolen(result)); */
if ( !SvOK(result) ) {
sqlite3_result_null( context );
} else if( SvROK(result) && SvTYPE(SvRV(result)) == SVt_PVAV ) {
av = (AV*)SvRV(result);
if ( av_len(av) == 1 ) {
presult2 = av_fetch(av, 0, 0);
ptype = av_fetch(av, 1, 0);
result2 = presult2 ? *presult2 : &PL_sv_undef;
type = ptype ? *ptype : &PL_sv_undef;
if ( SvIOK(type) ) {
switch(sqlite_type_from_odbc_type(SvIV(type))) {
case SQLITE_INTEGER:
sqlite3_result_int64( context, SvIV(result2) );
return;
case SQLITE_FLOAT:
sqlite3_result_double( context, SvNV(result2) );
return;
case SQLITE_BLOB:
s = SvPV(result2, len);
sqlite3_result_blob( context, s, len, SQLITE_TRANSIENT );
return;
case SQLITE_TEXT:
s = SvPV(result2, len);
sqlite3_result_text( context, s, len, SQLITE_TRANSIENT );
return;
}
}
}
sqlite3_result_error( context, "unexpected arrayref", 19 );
} else if( SvIOK_UV(result) ) {
if ((UV)(sqlite3_int64)UV_MAX == UV_MAX)
sqlite3_result_int64( context, (sqlite3_int64)SvUV(result));
@ -372,8 +405,18 @@ sqlite_is_number(pTHX_ const char *v, int sql_type)
if (!_sqlite_atoi64(v, &iv)) return 1;
}
if (sql_type != SQLITE_INTEGER) {
#ifdef USE_QUADMATH
sprintf(format, (has_plus ? "+%%.%dQf" : "%%.%dQf"), precision);
# if defined(WIN32)
/* On Windows quadmath, we need to use strtoflt128(), not atov() */
if (strEQ(form(format, strtoflt128(v, NULL)), v)) return 2;
# else
if (strEQ(form(format, atof(v)), v)) return 2;
# endif
#else
sprintf(format, (has_plus ? "+%%.%df" : "%%.%df" ), precision);
if (strEQ(form(format, atof(v)), v)) return 2;
#endif
}
return 0;
}
@ -396,16 +439,54 @@ sqlite_discon_all(SV *drh, imp_drh_t *imp_drh)
return FALSE; /* no way to do this */
}
#define _croak_invalid_value(name, value) \
croak("Invalid value (%s) given for %s", value, name);
/* Like SvUV but croaks on anything other than an unsigned int. */
static inline int
my_SvUV_strict(pTHX_ SV *input, const char* name)
{
if (SvUOK(input)) {
return SvUV(input);
}
const char* pv = SvPVbyte_nolen(input);
UV uv;
int numtype = grok_number(pv, strlen(pv), &uv);
/* Anything else is invalid: */
if (numtype != IS_NUMBER_IN_UV) _croak_invalid_value(name, pv);
return uv;
}
static inline dbd_sqlite_string_mode_t
_extract_sqlite_string_mode_from_sv( pTHX_ SV* input )
{
if (SvOK(input)) {
UV val = my_SvUV_strict(aTHX_ input, "sqlite_string_mode");
if (val >= _DBD_SQLITE_STRING_MODE_COUNT) {
_croak_invalid_value("sqlite_string_mode", SvPVbyte_nolen(input));
}
return val;
}
return DBD_SQLITE_STRING_MODE_PV;
}
int
sqlite_db_login6(SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *user, char *pass, SV *attr)
{
dTHX;
int rc;
HV *hv;
HV *hv = NULL;
SV **val;
int extended = 0;
int flag = 0;
int unicode = 0;
dbd_sqlite_string_mode_t string_mode = DBD_SQLITE_STRING_MODE_PV;
sqlite_trace(dbh, imp_dbh, 3, form("login '%s' (version %s)", dbname, sqlite3_version));
@ -428,13 +509,24 @@ sqlite_db_login6(SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *user, char *pa
hv_stores(hv, "ReadOnly", newSViv(1));
}
}
/* sqlite_unicode should be detected earlier, to register default functions correctly */
if (hv_exists(hv, "sqlite_unicode", 14)) {
/* sqlite_string_mode should be detected earlier, to register default functions correctly */
SV** string_mode_svp = hv_fetchs(hv, "sqlite_string_mode", 0);
if (string_mode_svp != NULL && SvOK(*string_mode_svp)) {
string_mode = _extract_sqlite_string_mode_from_sv(aTHX_ *string_mode_svp);
/* Legacy alternatives to sqlite_string_mode: */
} else if (hv_exists(hv, "sqlite_unicode", 14)) {
val = hv_fetch(hv, "sqlite_unicode", 14, 0);
unicode = (val && SvOK(*val)) ? SvIV(*val) : 0;
if ( (val && SvOK(*val)) ? SvIV(*val) : 0 ) {
string_mode = DBD_SQLITE_STRING_MODE_UNICODE_NAIVE;
}
} else if (hv_exists(hv, "unicode", 7)) {
val = hv_fetch(hv, "unicode", 7, 0);
unicode = (val && SvOK(*val)) ? SvIV(*val) : 0;
if ( (val && SvOK(*val)) ? SvIV(*val) : 0 ) {
string_mode = DBD_SQLITE_STRING_MODE_UNICODE_NAIVE;
}
}
}
rc = sqlite_open2(dbname, &(imp_dbh->db), flag, extended);
@ -443,7 +535,7 @@ sqlite_db_login6(SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *user, char *pa
}
DBIc_IMPSET_on(imp_dbh);
imp_dbh->unicode = unicode;
imp_dbh->string_mode = string_mode;
imp_dbh->functions = newAV();
imp_dbh->aggregates = newAV();
imp_dbh->collation_needed_callback = newSVsv( &PL_sv_undef );
@ -455,9 +547,20 @@ sqlite_db_login6(SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *user, char *pa
imp_dbh->extended_result_codes = extended;
imp_dbh->stmt_list = NULL;
imp_dbh->began_transaction = FALSE;
imp_dbh->prefer_numeric_type = FALSE;
sqlite3_busy_timeout(imp_dbh->db, SQL_TIMEOUT);
if (SvROK(attr)) {
hv = (HV*)SvRV(attr);
if (hv_exists(hv, "sqlite_defensive", 16)) {
val = hv_fetch(hv, "sqlite_defensive", 16, 0);
if (val && SvIOK(*val)) {
sqlite3_db_config(imp_dbh->db, SQLITE_DBCONFIG_DEFENSIVE, (int)SvIV(*val), 0);
}
}
}
#if 0
/*
** As of 1.26_06 foreign keys support was enabled by default,
@ -500,9 +603,7 @@ sqlite_db_do_sv(SV *dbh, imp_dbh_t *imp_dbh, SV *sv_statement)
}
/* sqlite3_prepare wants an utf8-encoded SQL statement */
if (imp_dbh->unicode) {
sv_utf8_upgrade(sv_statement);
}
DBD_SQLITE_PREP_SV_FOR_SQLITE(sv_statement, imp_dbh->string_mode);
statement = SvPV_nolen(sv_statement);
@ -689,6 +790,10 @@ sqlite_db_destroy(SV *dbh, imp_dbh_t *imp_dbh)
DBIc_IMPSET_off(imp_dbh);
}
#define _warn_deprecated_if_possible(old, new) \
if (DBIc_has(imp_dbh, DBIcf_WARN)) \
warn("\"%s\" attribute will be deprecated. Use \"%s\" instead.", old, new);
int
sqlite_db_STORE_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv, SV *valuesv)
{
@ -737,26 +842,48 @@ sqlite_db_STORE_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv, SV *valuesv)
sqlite3_extended_result_codes(imp_dbh->db, imp_dbh->extended_result_codes);
return TRUE;
}
if (strEQ(key, "sqlite_prefer_numeric_type")) {
imp_dbh->prefer_numeric_type = !(! SvTRUE(valuesv));
return TRUE;
}
if (strEQ(key, "sqlite_string_mode")) {
dbd_sqlite_string_mode_t string_mode = _extract_sqlite_string_mode_from_sv(aTHX_ valuesv);
#if PERL_UNICODE_DOES_NOT_WORK_WELL
if (string_mode & DBD_SQLITE_STRING_MODE_UNICODE_ANY) {
sqlite_trace(dbh, imp_dbh, 3, form("Unicode support is disabled for this version of perl."));
string_mode = DBD_SQLITE_STRING_MODE_PV;
}
#endif
imp_dbh->string_mode = string_mode;
return TRUE;
}
if (strEQ(key, "sqlite_unicode")) {
/* it's too early to warn the deprecation of sqlite_unicode as it's widely used */
#if PERL_UNICODE_DOES_NOT_WORK_WELL
sqlite_trace(dbh, imp_dbh, 3, form("Unicode support is disabled for this version of perl."));
imp_dbh->unicode = 0;
imp_dbh->string_mode = DBD_SQLITE_STRING_MODE_PV;
#else
imp_dbh->unicode = !(! SvTRUE(valuesv));
imp_dbh->string_mode = SvTRUE(valuesv) ? DBD_SQLITE_STRING_MODE_UNICODE_NAIVE : DBD_SQLITE_STRING_MODE_PV;
#endif
return TRUE;
}
if (strEQ(key, "unicode")) {
if (DBIc_has(imp_dbh, DBIcf_WARN))
warn("\"unicode\" attribute will be deprecated. Use \"sqlite_unicode\" instead.");
_warn_deprecated_if_possible(key, "sqlite_string_mode");
#if PERL_UNICODE_DOES_NOT_WORK_WELL
sqlite_trace(dbh, imp_dbh, 3, form("Unicode support is disabled for this version of perl."));
imp_dbh->unicode = 0;
imp_dbh->string_mode = DBD_SQLITE_STRING_MODE_PV;
#else
imp_dbh->unicode = !(! SvTRUE(valuesv));
imp_dbh->string_mode = SvTRUE(valuesv) ? DBD_SQLITE_STRING_MODE_UNICODE_NAIVE : DBD_SQLITE_STRING_MODE_PV;
#endif
return TRUE;
}
return FALSE;
}
@ -781,22 +908,21 @@ sqlite_db_FETCH_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv)
if (strEQ(key, "sqlite_extended_result_codes")) {
return sv_2mortal(newSViv(imp_dbh->extended_result_codes ? 1 : 0));
}
if (strEQ(key, "sqlite_unicode")) {
#if PERL_UNICODE_DOES_NOT_WORK_WELL
sqlite_trace(dbh, imp_dbh, 3, "Unicode support is disabled for this version of perl.");
return sv_2mortal(newSViv(0));
#else
return sv_2mortal(newSViv(imp_dbh->unicode ? 1 : 0));
#endif
if (strEQ(key, "sqlite_prefer_numeric_type")) {
return sv_2mortal(newSViv(imp_dbh->prefer_numeric_type ? 1 : 0));
}
if (strEQ(key, "unicode")) {
if (DBIc_has(imp_dbh, DBIcf_WARN))
warn("\"unicode\" attribute will be deprecated. Use \"sqlite_unicode\" instead.");
if (strEQ(key, "sqlite_string_mode")) {
return sv_2mortal(newSVuv(imp_dbh->string_mode));
}
if (strEQ(key, "sqlite_unicode") || strEQ(key, "unicode")) {
_warn_deprecated_if_possible(key, "sqlite_string_mode");
#if PERL_UNICODE_DOES_NOT_WORK_WELL
sqlite_trace(dbh, imp_dbh, 3, "Unicode support is disabled for this version of perl.");
return sv_2mortal(newSViv(0));
#else
return sv_2mortal(newSViv(imp_dbh->unicode ? 1 : 0));
return sv_2mortal(newSViv(imp_dbh->string_mode == DBD_SQLITE_STRING_MODE_UNICODE_NAIVE ? 1 : 0));
#endif
}
@ -829,7 +955,7 @@ sqlite_st_prepare_sv(SV *sth, imp_sth_t *imp_sth, SV *sv_statement, SV *attribs)
stmt_list_s * new_stmt;
D_imp_dbh_from_sth;
MY_CXT.last_dbh_is_unicode = imp_dbh->unicode;
MY_CXT.last_dbh_string_mode = imp_dbh->string_mode;
if (!DBIc_ACTIVE(imp_dbh)) {
sqlite_error(sth, -2, "attempt to prepare on inactive database handle");
@ -837,9 +963,7 @@ sqlite_st_prepare_sv(SV *sth, imp_sth_t *imp_sth, SV *sv_statement, SV *attribs)
}
/* sqlite3_prepare wants an utf8-encoded SQL statement */
if (imp_dbh->unicode) {
sv_utf8_upgrade(sv_statement);
}
DBD_SQLITE_PREP_SV_FOR_SQLITE(sv_statement, imp_dbh->string_mode);
statement = SvPV_nolen(sv_statement);
@ -953,10 +1077,15 @@ sqlite_st_execute(SV *sth, imp_sth_t *imp_sth)
const char *data;
int numtype = 0;
if (imp_dbh->unicode) {
sv_utf8_upgrade(value);
if (imp_dbh->string_mode & DBD_SQLITE_STRING_MODE_UNICODE_ANY) {
data = SvPVutf8(value, len);
}
else if (imp_dbh->string_mode == DBD_SQLITE_STRING_MODE_BYTES) {
data = SvPVbyte(value, len);
}
else {
data = SvPV(value, len);
}
/*
* XXX: For backward compatibility, it'd be better to
@ -1167,11 +1296,9 @@ sqlite_st_fetch(SV *sth, imp_sth_t *imp_sth)
}
}
sv_setpvn(AvARRAY(av)[i], val, len);
if (imp_dbh->unicode) {
SvUTF8_on(AvARRAY(av)[i]);
} else {
SvUTF8_off(AvARRAY(av)[i]);
}
DBD_SQLITE_UTF8_DECODE_IF_NEEDED(AvARRAY(av)[i], imp_dbh->string_mode);
break;
case SQLITE_BLOB:
sqlite_trace(sth, imp_sth, 5, form("fetch column %d as blob", i));
@ -1312,6 +1439,11 @@ sqlite_st_FETCH_attrib(SV *sth, imp_sth_t *imp_sth, SV *keysv)
croak_if_db_is_null();
croak_if_stmt_is_null();
if (!DBIc_ACTIVE(imp_dbh)) {
sqlite_error(sth, -2, "attempt to fetch on inactive database handle");
return FALSE;
}
if (strEQ(key, "sqlite_unprepared_statements")) {
return sv_2mortal(newSVpv(imp_sth->unprepared_statements, 0));
}
@ -1338,8 +1470,9 @@ sqlite_st_FETCH_attrib(SV *sth, imp_sth_t *imp_sth, SV *keysv)
/* if (dot) drop table name from field name */
/* fieldname = ++dot; */
SV *sv_fieldname = newSVpv(fieldname, 0);
if (imp_dbh->unicode)
SvUTF8_on(sv_fieldname);
DBD_SQLITE_UTF8_DECODE_IF_NEEDED(sv_fieldname, imp_dbh->string_mode);
av_store(av, n, sv_fieldname);
}
}
@ -1353,17 +1486,20 @@ sqlite_st_FETCH_attrib(SV *sth, imp_sth_t *imp_sth, SV *keysv)
av_extend(av, i);
retsv = sv_2mortal(newRV_noinc((SV*)av));
for (n = 0; n < i; n++) {
const char *fieldtype = sqlite3_column_decltype(imp_sth->stmt, n);
if (imp_dbh->prefer_numeric_type) {
int type = sqlite3_column_type(imp_sth->stmt, n);
/* warn("got type: %d = %s\n", type, fieldtype); */
type = sqlite_type_to_odbc_type(type);
/* av_store(av, n, newSViv(type)); */
av_store(av, n, newSViv(type));
} else {
const char *fieldtype = sqlite3_column_decltype(imp_sth->stmt, n);
if (fieldtype)
av_store(av, n, newSVpv(fieldtype, 0));
else
av_store(av, n, newSVpv("VARCHAR", 0));
}
}
}
else if (strEQ(key, "NULLABLE")) {
AV *av = newAV();
av_extend(av, i);
@ -1597,7 +1733,7 @@ SV *
sqlite_db_filename(pTHX_ SV *dbh)
{
D_imp_dbh(dbh);
const char *filename;
const char *filename = NULL;
if (!imp_dbh->db) {
return &PL_sv_undef;
@ -1630,7 +1766,7 @@ sqlite_db_busy_timeout(pTHX_ SV *dbh, SV *timeout )
}
static void
sqlite_db_func_dispatcher(int is_unicode, sqlite3_context *context, int argc, sqlite3_value **value)
sqlite_db_func_dispatcher(dbd_sqlite_string_mode_t string_mode, sqlite3_context *context, int argc, sqlite3_value **value)
{
dTHX;
dSP;
@ -1645,7 +1781,7 @@ sqlite_db_func_dispatcher(int is_unicode, sqlite3_context *context, int argc, sq
PUSHMARK(SP);
for ( i=0; i < argc; i++ ) {
XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ value[i], is_unicode));
XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ value[i], string_mode));
}
PUTBACK;
@ -1676,17 +1812,46 @@ sqlite_db_func_dispatcher(int is_unicode, sqlite3_context *context, int argc, sq
}
static void
sqlite_db_func_dispatcher_unicode(sqlite3_context *context, int argc, sqlite3_value **value)
sqlite_db_func_dispatcher_unicode_naive(sqlite3_context *context, int argc, sqlite3_value **value)
{
sqlite_db_func_dispatcher(1, context, argc, value);
sqlite_db_func_dispatcher(DBD_SQLITE_STRING_MODE_UNICODE_NAIVE, context, argc, value);
}
static void
sqlite_db_func_dispatcher_no_unicode(sqlite3_context *context, int argc, sqlite3_value **value)
sqlite_db_func_dispatcher_unicode_fallback(sqlite3_context *context, int argc, sqlite3_value **value)
{
sqlite_db_func_dispatcher(0, context, argc, value);
sqlite_db_func_dispatcher(DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK, context, argc, value);
}
static void
sqlite_db_func_dispatcher_unicode_strict(sqlite3_context *context, int argc, sqlite3_value **value)
{
sqlite_db_func_dispatcher(DBD_SQLITE_STRING_MODE_UNICODE_STRICT, context, argc, value);
}
static void
sqlite_db_func_dispatcher_bytes(sqlite3_context *context, int argc, sqlite3_value **value)
{
sqlite_db_func_dispatcher(DBD_SQLITE_STRING_MODE_BYTES, context, argc, value);
}
static void
sqlite_db_func_dispatcher_pv(sqlite3_context *context, int argc, sqlite3_value **value)
{
sqlite_db_func_dispatcher(DBD_SQLITE_STRING_MODE_PV, context, argc, value);
}
typedef void (*dispatch_func_t)(sqlite3_context*, int, sqlite3_value**);
static dispatch_func_t _FUNC_DISPATCHER[_DBD_SQLITE_STRING_MODE_COUNT] = {
sqlite_db_func_dispatcher_pv,
sqlite_db_func_dispatcher_bytes,
NULL, NULL,
sqlite_db_func_dispatcher_unicode_naive,
sqlite_db_func_dispatcher_unicode_fallback,
sqlite_db_func_dispatcher_unicode_strict,
};
int
sqlite_db_create_function(pTHX_ SV *dbh, const char *name, int argc, SV *func, int flags)
{
@ -1700,17 +1865,20 @@ sqlite_db_create_function(pTHX_ SV *dbh, const char *name, int argc, SV *func, i
}
/* Copy the function reference */
if (SvOK(func)) {
func_sv = newSVsv(func);
av_push( imp_dbh->functions, func_sv );
}
croak_if_db_is_null();
/* warn("create_function %s with %d args\n", name, argc); */
if (SvOK(func)) {
rc = sqlite3_create_function( imp_dbh->db, name, argc, SQLITE_UTF8|flags,
func_sv,
imp_dbh->unicode ? sqlite_db_func_dispatcher_unicode
: sqlite_db_func_dispatcher_no_unicode,
NULL, NULL );
func_sv, _FUNC_DISPATCHER[imp_dbh->string_mode], NULL, NULL );
} else {
rc = sqlite3_create_function( imp_dbh->db, name, argc, SQLITE_UTF8|flags, NULL, NULL, NULL, NULL );
}
if ( rc != SQLITE_OK ) {
sqlite_error(dbh, rc, form("sqlite_create_function failed with error %s", sqlite3_errmsg(imp_dbh->db)));
return FALSE;
@ -1766,6 +1934,21 @@ sqlite_db_load_extension(pTHX_ SV *dbh, const char *file, const char *proc)
#endif
SV* _lc(pTHX_ SV* sv) {
int i, l;
char* pv;
if (SvPOK(sv)) {
pv = SvPV_nolen(sv);
l = strlen(pv);
for(i = 0; i < l; i++) {
if (pv[i] >= 'A' && pv[i] <= 'Z') {
pv[i] = pv[i] - 'A' + 'a';
}
}
}
return sv;
}
HV*
sqlite_db_table_column_metadata(pTHX_ SV *dbh, SV *dbname, SV *tablename, SV *columnname)
{
@ -1802,7 +1985,7 @@ sqlite_db_table_column_metadata(pTHX_ SV *dbh, SV *dbname, SV *tablename, SV *co
#endif
if (rc == SQLITE_OK) {
hv_stores(metadata, "data_type", datatype ? newSVpv(datatype, 0) : newSV(0));
hv_stores(metadata, "data_type", datatype ? _lc(aTHX_ newSVpv(datatype, 0)) : newSV(0));
hv_stores(metadata, "collation_name", collseq ? newSVpv(collseq, 0) : newSV(0));
hv_stores(metadata, "not_null", newSViv(notnull));
hv_stores(metadata, "primary", newSViv(primary));
@ -1874,7 +2057,7 @@ sqlite_db_aggr_step_dispatcher(sqlite3_context *context,
{
dTHX;
dSP;
int i, is_unicode = 0; /* TODO : find out from db handle */
int i, string_mode = DBD_SQLITE_STRING_MODE_PV; /* TODO : find out from db handle */
aggrInfo *aggr;
aggr = sqlite3_aggregate_context(context, sizeof (aggrInfo));
@ -1896,7 +2079,7 @@ sqlite_db_aggr_step_dispatcher(sqlite3_context *context,
PUSHMARK(SP);
XPUSHs( sv_2mortal( newSVsv( aggr->aggr_inst ) ));
for ( i=0; i < argc; i++ ) {
XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ value[i], is_unicode));
XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ value[i], string_mode));
}
PUTBACK;
@ -2012,71 +2195,78 @@ sqlite_db_create_aggregate(pTHX_ SV *dbh, const char *name, int argc, SV *aggr_p
return TRUE;
}
#define SQLITE_DB_COLLATION_BASE(func, sv1, sv2) STMT_START { \
int cmp = 0; \
int n_retval, i; \
\
ENTER; \
SAVETMPS; \
PUSHMARK(SP); \
XPUSHs( sv_2mortal( sv1 ) ); \
XPUSHs( sv_2mortal( sv2 ) ); \
PUTBACK; \
n_retval = call_sv(func, G_SCALAR); \
SPAGAIN; \
if (n_retval != 1) { \
warn("collation function returned %d arguments", n_retval); \
} \
for(i = 0; i < n_retval; i++) { \
cmp = POPi; \
} \
PUTBACK; \
FREETMPS; \
LEAVE; \
\
return cmp; \
} STMT_END
int
sqlite_db_collation_dispatcher(void *func, int len1, const void *string1,
int len2, const void *string2)
{
dTHX;
dSP;
int cmp = 0;
int n_retval, i;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs( sv_2mortal( newSVpvn( string1, len1) ) );
XPUSHs( sv_2mortal( newSVpvn( string2, len2) ) );
PUTBACK;
n_retval = call_sv(func, G_SCALAR);
SPAGAIN;
if (n_retval != 1) {
warn("collation function returned %d arguments", n_retval);
}
for(i = 0; i < n_retval; i++) {
cmp = POPi;
}
PUTBACK;
FREETMPS;
LEAVE;
return cmp;
SQLITE_DB_COLLATION_BASE(func, newSVpvn( string1, len1), newSVpvn( string2, len2));
}
int
sqlite_db_collation_dispatcher_utf8(void *func, int len1, const void *string1,
sqlite_db_collation_dispatcher_utf8_naive(void *func, int len1, const void *string1,
int len2, const void *string2)
{
dTHX;
dSP;
int cmp = 0;
int n_retval, i;
SV *sv1, *sv2;
ENTER;
SAVETMPS;
PUSHMARK(SP);
sv1 = newSVpvn(string1, len1);
SvUTF8_on(sv1);
sv2 = newSVpvn(string2, len2);
SvUTF8_on(sv2);
XPUSHs( sv_2mortal( sv1 ) );
XPUSHs( sv_2mortal( sv2 ) );
PUTBACK;
n_retval = call_sv(func, G_SCALAR);
SPAGAIN;
if (n_retval != 1) {
warn("collation function returned %d arguments", n_retval);
SQLITE_DB_COLLATION_BASE(func, newSVpvn_flags( string1, len1, SVf_UTF8), newSVpvn_flags( string2, len2, SVf_UTF8));
}
for(i = 0; i < n_retval; i++) {
cmp = POPi;
}
PUTBACK;
FREETMPS;
LEAVE;
return cmp;
int
sqlite_db_collation_dispatcher_utf8_fallback(void *func, int len1, const void *string1,
int len2, const void *string2)
{
dTHX;
dSP;
SV* sv1 = newSVpvn( string1, len1);
SV* sv2 = newSVpvn( string2, len2);
DBD_SQLITE_UTF8_DECODE_WITH_FALLBACK(sv1);
DBD_SQLITE_UTF8_DECODE_WITH_FALLBACK(sv2);
SQLITE_DB_COLLATION_BASE(func, sv1, sv2);
}
typedef int (*collation_dispatch_func_t)(void *, int, const void *, int, const void *);
static collation_dispatch_func_t _COLLATION_DISPATCHER[_DBD_SQLITE_STRING_MODE_COUNT] = {
sqlite_db_collation_dispatcher,
sqlite_db_collation_dispatcher,
NULL, NULL,
sqlite_db_collation_dispatcher_utf8_naive,
sqlite_db_collation_dispatcher_utf8_fallback,
sqlite_db_collation_dispatcher_utf8_fallback,
};
int
sqlite_db_create_collation(pTHX_ SV *dbh, const char *name, SV *func)
{
@ -2112,8 +2302,7 @@ sqlite_db_create_collation(pTHX_ SV *dbh, const char *name, SV *func)
rv = sqlite3_create_collation(
imp_dbh->db, name, SQLITE_UTF8,
func_sv,
imp_dbh->unicode ? sqlite_db_collation_dispatcher_utf8
: sqlite_db_collation_dispatcher
_COLLATION_DISPATCHER[imp_dbh->string_mode]
);
if ( rv != SQLITE_OK ) {
@ -2599,6 +2788,49 @@ sqlite_db_backup_from_file(pTHX_ SV *dbh, char *filename)
#endif
}
int
sqlite_db_backup_from_dbh(pTHX_ SV *dbh, SV *from)
{
D_imp_dbh(dbh);
#if SQLITE_VERSION_NUMBER >= 3006011
int rc;
sqlite3_backup *pBackup;
imp_dbh_t *imp_dbh_from = (imp_dbh_t *)DBIh_COM(from);
if (!DBIc_ACTIVE(imp_dbh)) {
sqlite_error(dbh, -2, "attempt to backup from file on inactive database handle");
return FALSE;
}
if (!DBIc_ACTIVE(imp_dbh_from)) {
sqlite_error(dbh, -2, "attempt to backup from inactive database handle");
return FALSE;
}
croak_if_db_is_null();
/* COMPAT: sqlite3_backup_* are only available for 3006011 or newer */
pBackup = sqlite3_backup_init(imp_dbh->db, "main", imp_dbh_from->db, "main");
if (pBackup) {
(void)sqlite3_backup_step(pBackup, -1);
(void)sqlite3_backup_finish(pBackup);
}
rc = sqlite3_errcode(imp_dbh->db);
if ( rc != SQLITE_OK ) {
sqlite_error(dbh, rc, form("sqlite_backup_from_file failed with error %s", sqlite3_errmsg(imp_dbh->db)));
return FALSE;
}
return TRUE;
#else
sqlite_error(dbh, SQLITE_ERROR, form("backup feature requires SQLite 3.6.11 and newer"));
return FALSE;
#endif
}
/* Accesses the SQLite Online Backup API, and copies the currently loaded
* database into the passed filename.
* Usual usage of this would be when you're operating on the :memory:
@ -2647,6 +2879,117 @@ sqlite_db_backup_to_file(pTHX_ SV *dbh, char *filename)
#endif
}
int
sqlite_db_backup_to_dbh(pTHX_ SV *dbh, SV *to)
{
D_imp_dbh(dbh);
#if SQLITE_VERSION_NUMBER >= 3006011
int rc;
sqlite3_backup *pBackup;
imp_dbh_t *imp_dbh_to = (imp_dbh_t *)DBIh_COM(to);
if (!DBIc_ACTIVE(imp_dbh)) {
sqlite_error(dbh, -2, "attempt to backup to file on inactive database handle");
return FALSE;
}
if (!DBIc_ACTIVE(imp_dbh_to)) {
sqlite_error(dbh, -2, "attempt to backup to inactive database handle");
return FALSE;
}
croak_if_db_is_null();
/* COMPAT: sqlite3_backup_* are only available for 3006011 or newer */
pBackup = sqlite3_backup_init(imp_dbh_to->db, "main", imp_dbh->db, "main");
if (pBackup) {
(void)sqlite3_backup_step(pBackup, -1);
(void)sqlite3_backup_finish(pBackup);
}
rc = sqlite3_errcode(imp_dbh_to->db);
if ( rc != SQLITE_OK ) {
sqlite_error(dbh, rc, form("sqlite_backup_to_file failed with error %s", sqlite3_errmsg(imp_dbh->db)));
return FALSE;
}
return TRUE;
#else
sqlite_error(dbh, SQLITE_ERROR, form("backup feature requires SQLite 3.6.11 and newer"));
return FALSE;
#endif
}
int
sqlite_db_limit(pTHX_ SV *dbh, int id, int new_value)
{
D_imp_dbh(dbh);
return sqlite3_limit(imp_dbh->db, id, new_value);
}
int
sqlite_db_config(pTHX_ SV *dbh, int id, int new_value)
{
D_imp_dbh(dbh);
int ret;
int rc = -1;
switch (id) {
case SQLITE_DBCONFIG_LOOKASIDE:
sqlite_error(dbh, rc, "SQLITE_DBCONFIG_LOOKASIDE is not supported");
return FALSE;
case SQLITE_DBCONFIG_MAINDBNAME:
sqlite_error(dbh, rc, "SQLITE_DBCONFIG_MAINDBNAME is not supported");
return FALSE;
case SQLITE_DBCONFIG_ENABLE_FKEY:
case SQLITE_DBCONFIG_ENABLE_TRIGGER:
case SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER:
case SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION:
case SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE:
case SQLITE_DBCONFIG_ENABLE_QPSG:
case SQLITE_DBCONFIG_TRIGGER_EQP:
case SQLITE_DBCONFIG_RESET_DATABASE:
case SQLITE_DBCONFIG_DEFENSIVE:
case SQLITE_DBCONFIG_WRITABLE_SCHEMA:
case SQLITE_DBCONFIG_LEGACY_ALTER_TABLE:
case SQLITE_DBCONFIG_DQS_DML:
case SQLITE_DBCONFIG_DQS_DDL:
rc = sqlite3_db_config(imp_dbh->db, id, new_value, &ret);
break;
default:
sqlite_error(dbh, rc, form("Unknown config id: %d", id));
return FALSE;
}
if ( rc != SQLITE_OK ) {
sqlite_error(dbh, rc, form("sqlite_db_config failed with error %s", sqlite3_errmsg(imp_dbh->db)));
return FALSE;
}
return ret;
}
int
sqlite_db_get_autocommit(pTHX_ SV *dbh)
{
D_imp_dbh(dbh);
return sqlite3_get_autocommit(imp_dbh->db);
}
int
sqlite_db_txn_state(pTHX_ SV *dbh, SV *schema)
{
#if SQLITE_VERSION_NUMBER >= 3034000
D_imp_dbh(dbh);
if (SvOK(schema) && SvPOK(schema)) {
return sqlite3_txn_state(imp_dbh->db, SvPV_nolen(schema));
} else {
return sqlite3_txn_state(imp_dbh->db, NULL);
}
#else
return -1;
#endif
}
#include "dbdimp_tokenizer.inc"
#include "dbdimp_virtual_table.inc"

View file

@ -7,8 +7,24 @@
#define MY_CXT_KEY "DBD::SQLite::_guts" XS_VERSION
typedef enum {
DBD_SQLITE_STRING_MODE_PV,
DBD_SQLITE_STRING_MODE_BYTES,
/* Leave space here so that we can use DBD_SQLITE_STRING_MODE_UNICODE_ANY
as a means of checking for any unicode mode. */
DBD_SQLITE_STRING_MODE_UNICODE_NAIVE = 4,
DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK,
DBD_SQLITE_STRING_MODE_UNICODE_STRICT,
_DBD_SQLITE_STRING_MODE_COUNT,
} dbd_sqlite_string_mode_t;
#define DBD_SQLITE_STRING_MODE_UNICODE_ANY DBD_SQLITE_STRING_MODE_UNICODE_NAIVE
typedef struct {
int last_dbh_is_unicode;
dbd_sqlite_string_mode_t last_dbh_string_mode;
} my_cxt_t;
#define PERL_UNICODE_DOES_NOT_WORK_WELL \
@ -22,6 +38,41 @@ typedef struct {
#define sqlite3_int64 sqlite_int64
#endif
#define DBD_SQLITE_UTF8_DECODE_NAIVE(sv) SvUTF8_on(sv)
#define DBD_SQLITE_UTF8_DECODE_CHECKED(sv, onfail) ( \
is_utf8_string((U8*) SvPVX(sv), SvCUR(sv)) \
? SvUTF8_on(sv) \
: onfail("Received invalid UTF-8 from SQLite; cannot decode!") \
)
#define DBD_SQLITE_UTF8_DECODE_WITH_FALLBACK(sv) ( \
DBD_SQLITE_UTF8_DECODE_CHECKED(sv, warn) \
)
#define DBD_SQLITE_UTF8_DECODE_STRICT(sv) ( \
DBD_SQLITE_UTF8_DECODE_CHECKED(sv, croak) \
)
#define DBD_SQLITE_PREP_SV_FOR_SQLITE(sv, string_mode) STMT_START { \
if (string_mode & DBD_SQLITE_STRING_MODE_UNICODE_ANY) { \
sv_utf8_upgrade(sv); \
} \
else if (string_mode == DBD_SQLITE_STRING_MODE_BYTES) { \
sv_utf8_downgrade(sv, 0); \
} \
} STMT_END
#define DBD_SQLITE_UTF8_DECODE_IF_NEEDED(sv, string_mode) ( \
string_mode == DBD_SQLITE_STRING_MODE_UNICODE_NAIVE \
? DBD_SQLITE_UTF8_DECODE_NAIVE(sv) \
: string_mode == DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK \
? DBD_SQLITE_UTF8_DECODE_WITH_FALLBACK(sv) \
: string_mode == DBD_SQLITE_STRING_MODE_UNICODE_STRICT \
? DBD_SQLITE_UTF8_DECODE_STRICT(sv) \
: 0 \
)
/* A linked list of statements prepared by this module */
typedef struct stmt_list_s stmt_list_s;
@ -41,7 +92,7 @@ struct imp_dbh_st {
dbih_dbc_t com;
/* sqlite specific bits */
sqlite3 *db;
bool unicode;
dbd_sqlite_string_mode_t string_mode;
bool handle_binary_nulls;
int timeout;
AV *functions;
@ -53,6 +104,7 @@ struct imp_dbh_st {
int extended_result_codes;
stmt_list_s * stmt_list;
bool began_transaction;
bool prefer_numeric_type;
};
/* Statement Handle */
@ -116,6 +168,8 @@ int sqlite_bind_col( SV *sth, imp_sth_t *imp_sth, SV *col, SV *ref, IV sql_type,
int sqlite_db_busy_timeout (pTHX_ SV *dbh, SV *timeout );
int sqlite_db_backup_from_file(pTHX_ SV *dbh, char *filename);
int sqlite_db_backup_to_file(pTHX_ SV *dbh, char *filename);
int sqlite_db_backup_from_dbh(pTHX_ SV *dbh, SV *from);
int sqlite_db_backup_to_dbh(pTHX_ SV *dbh, SV *to);
void sqlite_db_collation_needed(pTHX_ SV *dbh, SV *callback );
SV* sqlite_db_commit_hook( pTHX_ SV *dbh, SV *hook );
SV* sqlite_db_rollback_hook( pTHX_ SV *dbh, SV *hook );
@ -131,6 +185,10 @@ int sqlite_db_register_fts3_perl_tokenizer(pTHX_ SV *dbh);
HV* _sqlite_status(int reset);
HV* _sqlite_st_status(pTHX_ SV *sth, int reset);
int sqlite_db_create_module(pTHX_ SV *dbh, const char *name, const char *perl_class);
int sqlite_db_limit(pTHX_ SV *dbh, int id, int new_value);
int sqlite_db_config(pTHX_ SV *dbh, int id, int new_value);
int sqlite_db_get_autocommit(pTHX_ SV *dbh);
int sqlite_db_txn_state(pTHX_ SV *dbh, SV *schema);
int sqlite_db_do_sv(SV *dbh, imp_dbh_t *imp_dbh, SV *sv_statement);
void init_cxt();

View file

@ -12,8 +12,8 @@ typedef struct perl_tokenizer_cursor {
/* members below are only used if the input string is in utf8 */
const char *pInput; /* input we are tokenizing */
const char *lastByteOffset; /* offset into pInput */
int lastCharOffset; /* char offset corresponding to lastByteOffset */
const char *currentByte; /* pointer into pInput */
int currentChar; /* char position corresponding to currentByte */
} perl_tokenizer_cursor;
/*
@ -94,6 +94,30 @@ static int perl_tokenizer_Open(
SV *perl_string;
int n_retval;
/* build a Perl copy of the input string */
if (nBytes < 0) { /* we get -1 from fts3. Don't know why ! */
nBytes = strlen(pInput);
}
/* SVs_TEMP will call sv_2mortal */
perl_string = newSVpvn_flags(pInput, nBytes, SVs_TEMP);
switch (MY_CXT.last_dbh_string_mode) {
DBD_SQLITE_STRING_MODE_UNICODE_NAIVE:
DBD_SQLITE_UTF8_DECODE_NAIVE(perl_string);
break;
DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK:
DBD_SQLITE_STRING_MODE_UNICODE_STRICT:
DBD_SQLITE_UTF8_DECODE_WITH_FALLBACK(perl_string);
break;
default:
break;
}
DBD_SQLITE_UTF8_DECODE_IF_NEEDED(perl_string, MY_CXT.last_dbh_string_mode);
perl_tokenizer *t = (perl_tokenizer *)pTokenizer;
/* allocate and initialize the cursor struct */
@ -102,29 +126,17 @@ static int perl_tokenizer_Open(
memset(c, 0, sizeof(*c));
*ppCursor = &c->base;
/* flags for creating the Perl SV containing the input string */
flags = SVs_TEMP; /* will call sv_2mortal */
/* special handling if working with utf8 strings */
if (MY_CXT.last_dbh_is_unicode) {
if (MY_CXT.last_dbh_string_mode & DBD_SQLITE_STRING_MODE_UNICODE_ANY) {
/* data to keep track of byte offsets */
c->lastByteOffset = c->pInput = pInput;
c->lastCharOffset = 0;
/* string passed to Perl needs to be flagged as utf8 */
flags |= SVf_UTF8;
/* data to keep track of byte positions */
c->currentByte = c->pInput = pInput;
c->currentChar = 0;
}
ENTER;
SAVETMPS;
/* build a Perl copy of the input string */
if (nBytes < 0) { /* we get -1 from fts3. Don't know why ! */
nBytes = strlen(pInput);
}
perl_string = newSVpvn_flags(pInput, nBytes, flags);
/* call the tokenizer coderef */
PUSHMARK(SP);
XPUSHs(perl_string);
@ -134,7 +146,7 @@ static int perl_tokenizer_Open(
/* store the cursor coderef returned by the tokenizer */
if (n_retval != 1) {
warn("tokenizer returned %d arguments", n_retval);
warn("tokenizer returned %d arguments, expected 1", n_retval);
}
c->coderef = newSVsv(POPs);
@ -164,17 +176,17 @@ static int perl_tokenizer_Close(sqlite3_tokenizer_cursor *pCursor){
*/
static int perl_tokenizer_Next(
sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by perl_tokenizer_Open */
const char **ppToken, /* OUT: *ppToken is the token text */
int *pnBytes, /* OUT: Number of bytes in token */
int *piStartOffset, /* OUT: Starting offset of token */
int *piEndOffset, /* OUT: Ending offset of token */
int *piPosition /* OUT: Position integer of token */
const char **ppToken, /* OUT: Normalized text for token */
int *pnBytes, /* OUT: Number of bytes in normalized text */
int *piStartOffset, /* Starting offset of token. IN : char offset; OUT : byte offset */
int *piEndOffset, /* Ending offset of token. IN : char offset; OUT : byte offset */
int *piPosition /* OUT: Number of tokens returned before this one */
){
perl_tokenizer_cursor *c = (perl_tokenizer_cursor *) pCursor;
int result;
int n_retval;
char *token;
char *byteOffset;
char *nextByte;
STRLEN n_a; /* this is required for older perls < 5.8.8 */
I32 hop;
@ -197,7 +209,7 @@ static int perl_tokenizer_Next(
/* otherwise, get token details from the return list */
else {
if (n_retval != 5) {
warn("tokenizer cursor returned %d arguments", n_retval);
warn("tokenizer cursor returned %d arguments, expected 5", n_retval);
}
*piPosition = POPi;
*piEndOffset = POPi;
@ -206,21 +218,30 @@ static int perl_tokenizer_Next(
token = POPpx;
if (c->pInput) { /* if working with utf8 data */
/* compute first hop : nb of chars from last position to the start of the token */
hop = *piStartOffset - c->currentChar;
/* recompute *pnBytes in bytes, not in chars */
*pnBytes = strlen(token);
/* hop: advance to the first byte in token */
nextByte = (char*)utf8_hop((U8*)c->currentByte, hop);
/* recompute start/end offsets in bytes, not in chars */
hop = *piStartOffset - c->lastCharOffset;
byteOffset = (char*)utf8_hop((U8*)c->lastByteOffset, hop);
/* compute 2nd hop : nb of chars from start of the token to end of token */
hop = *piEndOffset - *piStartOffset;
*piStartOffset = byteOffset - c->pInput;
byteOffset = (char*)utf8_hop((U8*)byteOffset, hop);
*piEndOffset = byteOffset - c->pInput;
/* remember where we are for next round */
c->lastCharOffset = *piEndOffset,
c->lastByteOffset = byteOffset;
/* now recompute the start offset in bytes, not in chars */
*piStartOffset = nextByte - c->pInput;
/* 2nd hop: advance past to the last byte in token */
nextByte = (char*)utf8_hop((U8*)nextByte, hop);
/* remember current position (useful for the next invocation) */
c->currentChar = *piEndOffset;
c->currentByte = nextByte;
/* now recompute the end offset in bytes, not in chars */
*piEndOffset = nextByte - c->pInput;
/* compute the size of the normalized token in bytes, not in chars */
*pnBytes = strlen(token);
}
/* make sure we have enough storage for copying the token */
@ -232,8 +253,7 @@ static int perl_tokenizer_Next(
c->pToken = pNew;
}
/* need to copy the token into the C cursor before perl frees that
memory */
/* need to copy the token into the C cursor before perl frees that memory */
memcpy(c->pToken, token, *pnBytes);
*ppToken = c->pToken;

View file

@ -47,6 +47,44 @@ static int _call_perl_vtab_method(sqlite3_vtab *pVTab,
}
/* RT-124941: it seems better to prefer PV where appropriate */
static void
sqlite_set_result_for_vtable(pTHX_ sqlite3_context *context, SV *result, int is_error)
{
STRLEN len;
char *s;
sqlite3_int64 iv;
if ( is_error ) {
s = SvPV(result, len);
sqlite3_result_error( context, s, len );
return;
}
/* warn("result: %s\n", SvPV_nolen(result)); */
if ( !SvOK(result) ) {
sqlite3_result_null( context );
} else if ( SvPOK(result) ) {
s = SvPV(result, len);
sqlite3_result_text( context, s, len, SQLITE_TRANSIENT );
} else if( SvIOK_UV(result) ) {
if ((UV)(sqlite3_int64)UV_MAX == UV_MAX)
sqlite3_result_int64( context, (sqlite3_int64)SvUV(result));
else {
s = SvPV(result, len);
sqlite3_result_text( context, s, len, SQLITE_TRANSIENT );
}
} else if ( !_sqlite_atoi64(SvPV(result, len), &iv) ) {
sqlite3_result_int64( context, iv );
} else if ( SvNOK(result) && ( sizeof(NV) == sizeof(double) || SvNVX(result) == (double) SvNVX(result) ) ) {
sqlite3_result_double( context, SvNV(result));
} else {
s = SvPV(result, len);
sqlite3_result_text( context, s, len, SQLITE_TRANSIENT );
}
}
static int perl_vt_New(const char *method,
sqlite3 *db, void *pAux,
@ -394,7 +432,7 @@ static int perl_vt_Filter( sqlite3_vtab_cursor *pVtabCursor,
dSP;
dMY_CXT;
int i, count;
int is_unicode = MY_CXT.last_dbh_is_unicode;
dbd_sqlite_string_mode_t string_mode = MY_CXT.last_dbh_string_mode;
ENTER;
SAVETMPS;
@ -405,7 +443,7 @@ static int perl_vt_Filter( sqlite3_vtab_cursor *pVtabCursor,
XPUSHs(sv_2mortal(newSViv(idxNum)));
XPUSHs(sv_2mortal(newSVpv(idxStr, 0)));
for(i = 0; i < argc; i++) {
XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ argv[i], is_unicode));
XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ argv[i], string_mode));
}
PUTBACK;
count = call_method("FILTER", G_VOID);
@ -446,7 +484,8 @@ static int perl_vt_Next(sqlite3_vtab_cursor *pVtabCursor){
static int perl_vt_Eof(sqlite3_vtab_cursor *pVtabCursor){
dTHX;
dSP;
int count, eof;
int count;
int eof = 1;
ENTER;
SAVETMPS;
@ -499,7 +538,7 @@ static int perl_vt_Column(sqlite3_vtab_cursor *pVtabCursor,
}
else {
SV *result = POPs;
sqlite_set_result(aTHX_ context, result, 0 );
sqlite_set_result_for_vtable(aTHX_ context, result, 0 );
rc = SQLITE_OK;
}
@ -549,7 +588,7 @@ static int perl_vt_Update( sqlite3_vtab *pVTab,
dSP;
dMY_CXT;
int count, i;
int is_unicode = MY_CXT.last_dbh_is_unicode;
dbd_sqlite_string_mode_t string_mode = MY_CXT.last_dbh_string_mode;
int rc = SQLITE_ERROR;
SV *rowidsv;
@ -560,7 +599,7 @@ static int perl_vt_Update( sqlite3_vtab *pVTab,
PUSHMARK(SP);
XPUSHs(((perl_vtab *) pVTab)->perl_vtab_obj);
for(i = 0; i < argc; i++) {
XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ argv[i], is_unicode));
XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ argv[i], string_mode));
}
PUTBACK;
count = call_method ("_SQLITE_UPDATE", G_SCALAR);
@ -665,8 +704,9 @@ static int perl_vt_FindFunction(sqlite3_vtab *pVTab,
/* return function information for sqlite3 within *pxFunc and *ppArg */
is_overloaded = coderef && SvTRUE(coderef);
if (is_overloaded) {
*pxFunc = MY_CXT.last_dbh_is_unicode ? sqlite_db_func_dispatcher_unicode
: sqlite_db_func_dispatcher_no_unicode;
*pxFunc = _FUNC_DISPATCHER[MY_CXT.last_dbh_string_mode];
*ppArg = coderef;
}
@ -775,6 +815,7 @@ sqlite_db_destroy_module_data(void *pAux)
/* free module memory */
SvREFCNT_dec(init_data->dbh);
sqlite3_free((char *)init_data->perl_class);
sqlite3_free(init_data);
PUTBACK;
FREETMPS;

216
inc/Test/FailWarnings.pm Normal file
View file

@ -0,0 +1,216 @@
use 5.008001;
use strict;
use warnings;
package Test::FailWarnings;
# ABSTRACT: Add test failures if warnings are caught
our $VERSION = '0.008'; # VERSION
use Test::More 0.86;
use Cwd qw/getcwd/;
use File::Spec;
use Carp;
our $ALLOW_DEPS = 0;
our @ALLOW_FROM = ();
my $ORIG_DIR = getcwd(); # cache in case handler runs after a chdir
sub import {
my ( $class, @args ) = @_;
croak("import arguments must be key/value pairs")
unless @args % 2 == 0;
my %opts = @args;
$ALLOW_DEPS = $opts{'-allow_deps'};
if ( $opts{'-allow_from'} ) {
@ALLOW_FROM =
ref $opts{'-allow_from'} ? @{ $opts{'-allow_from'} } : $opts{'-allow_from'};
}
$SIG{__WARN__} = \&handler;
}
sub handler {
my $msg = shift;
$msg = '' unless defined $msg;
chomp $msg;
my ( $package, $filename, $line ) = _find_source();
# shortcut if ignoring dependencies and warning did not
# come from something local
if ($ALLOW_DEPS) {
$filename = File::Spec->abs2rel( $filename, $ORIG_DIR )
if File::Spec->file_name_is_absolute($filename);
return if $filename !~ /^(?:t|xt|lib|blib)/;
}
return if grep { $package eq $_ } @ALLOW_FROM;
if ( $msg !~ m/at .*? line \d/ ) {
chomp $msg;
$msg = "'$msg' at $filename line $line.";
}
else {
$msg = "'$msg'";
}
my $builder = Test::More->builder;
$builder->ok( 0, "Test::FailWarnings should catch no warnings" )
or $builder->diag("Warning was $msg");
}
sub _find_source {
my $i = 1;
while (1) {
my ( $pkg, $filename, $line ) = caller( $i++ );
return caller( $i - 2 ) unless defined $pkg;
next if $pkg =~ /^(?:Carp|warnings)/;
return ( $pkg, $filename, $line );
}
}
1;
# vim: ts=4 sts=4 sw=4 et:
__END__
=pod
=encoding utf-8
=head1 NAME
Test::FailWarnings - Add test failures if warnings are caught
=head1 VERSION
version 0.008
=head1 SYNOPSIS
Test file:
use strict;
use warnings;
use Test::More;
use Test::FailWarnings;
ok( 1, "first test" );
ok( 1 + "lkadjaks", "add non-numeric" );
done_testing;
Output:
ok 1 - first test
not ok 2 - Test::FailWarnings should catch no warnings
# Failed test 'Test::FailWarnings should catch no warnings'
# at t/bin/main-warn.pl line 7.
# Warning was 'Argument "lkadjaks" isn't numeric in addition (+) at t/bin/main-warn.pl line 7.'
ok 3 - add non-numeric
1..3
# Looks like you failed 1 test of 3.
=head1 DESCRIPTION
This module hooks C<$SIG{__WARN__}> and converts warnings to L<Test::More>
C<fail()> calls. It is designed to be used with C<done_testing>, when you
don't need to know the test count in advance.
Just as with L<Test::NoWarnings>, this does not catch warnings if other things
localize C<$SIG{__WARN__}>, as this is designed to catch I<unhandled> warnings.
=for Pod::Coverage handler
=head1 USAGE
=head2 Overriding C<$SIG{__WARN__}>
On C<import>, C<$SIG{__WARN__}> is replaced with
C<Test::FailWarnings::handler>.
use Test::FailWarnings; # global
If you don't want global replacement, require the module instead and localize
in whatever scope you want.
require Test::FailWarnings;
{
local $SIG{__WARN__} = \&Test::FailWarnings::handler;
# ... warnings will issue fail() here
}
When the handler reports on the source of the warning, it will look past
any calling packages starting with C<Carp> or C<warnings> to try to detect
the real origin of the warning.
=head2 Allowing warnings from dependencies
If you want to ignore failures from outside your own code, you can set
C<$Test::FailWarnings::ALLOW_DEPS> to a true value. You can
do that on the C<use> line with C<< -allow_deps >>.
use Test::FailWarnings -allow_deps => 1;
When true, warnings will only be thrown if they appear to originate from a filename
matching C<< qr/^(?:t|xt|lib|blib)/ >>
=head2 Allowing warnings from specific modules
If you want to white-list specific modules only, you can add their package
names to C<@Test::NoWarnings::ALLOW_FROM>. You can do that on the C<use> line
with C<< -allow_from >>.
use Test::FailWarnings -allow_from => [ qw/Annoying::Module/ ];
=head1 SEE ALSO
=over 4
=item *
L<Test::NoWarnings> -- catches warnings and reports in an C<END> block. Not (yet) friendly with C<done_testing>.
=item *
L<Test::Warnings> -- a replacement for Test::NoWarnings that works with done_testing
=item *
L<Test::Warn> -- test for warnings without triggering failures from this modules
=back
=for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
=head1 SUPPORT
=head2 Bugs / Feature Requests
Please report any bugs or feature requests through the issue tracker
at L<https://github.com/dagolden/Test-FailWarnings/issues>.
You will be notified automatically of any progress on your issue.
=head2 Source Code
This is open source software. The code repository is available for
public review and contribution under the terms of the license.
L<https://github.com/dagolden/Test-FailWarnings>
git clone https://github.com/dagolden/Test-FailWarnings.git
=head1 AUTHOR
David Golden <dagolden@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is Copyright (c) 2013 by David Golden.
This is free software, licensed under:
The Apache License, Version 2.0, January 2004
=cut

View file

@ -1,301 +0,0 @@
package Test::NoWarnings;
use 5.006;
use strict;
use warnings;
use Carp ();
use Exporter ();
use Test::Builder ();
use Test::NoWarnings::Warning ();
use vars qw( $VERSION @EXPORT_OK @ISA $do_end_test );
BEGIN {
$VERSION = '1.02';
@ISA = 'Exporter';
@EXPORT_OK = qw(
clear_warnings had_no_warnings warnings
);
# Do we add the warning test at the end?
$do_end_test = 0;
}
my $TEST = Test::Builder->new;
my $PID = $$;
my @WARNINGS = ();
$SIG{__WARN__} = make_catcher(\@WARNINGS);
sub import {
$do_end_test = 1;
goto &Exporter::import;
}
# the END block must be after the "use Test::Builder" to make sure it runs
# before Test::Builder's end block
# only run the test if there have been other tests
END {
had_no_warnings() if $do_end_test;
}
sub make_warning {
local $SIG{__WARN__};
my $msg = shift;
my $warning = Test::NoWarnings::Warning->new;
$warning->setMessage($msg);
$warning->fillTest($TEST);
$warning->fillTrace(__PACKAGE__);
$Carp::Internal{__PACKAGE__.""}++;
local $Carp::CarpLevel = $Carp::CarpLevel + 1;
$warning->fillCarp($msg);
$Carp::Internal{__PACKAGE__.""}--;
return $warning;
}
# this make a subroutine which can be used in $SIG{__WARN__}
# it takes one argument, a ref to an array
# it will push the details of the warning onto the end of the array.
sub make_catcher {
my $array = shift;
return sub {
my $msg = shift;
$Carp::Internal{__PACKAGE__.""}++;
push(@$array, make_warning($msg));
$Carp::Internal{__PACKAGE__.""}--;
return $msg;
};
}
sub had_no_warnings {
return 0 if $$ != $PID;
local $SIG{__WARN__};
my $name = shift || "no warnings";
my $ok;
my $diag;
if ( @WARNINGS == 0 ) {
$ok = 1;
} else {
$ok = 0;
$diag = "There were ".@WARNINGS." warning(s)\n";
$diag .= join "----------\n", map { $_->toString } @WARNINGS;
}
$TEST->ok($ok, $name) || $TEST->diag($diag);
return $ok;
}
sub clear_warnings {
local $SIG{__WARN__};
@WARNINGS = ();
}
sub warnings {
local $SIG{__WARN__};
return @WARNINGS;
}
sub builder {
local $SIG{__WARN__};
if ( @_ ) {
$TEST = shift;
}
return $TEST;
}
1;
__END__
=pod
=head1 NAME
Test::NoWarnings - Make sure you didn't emit any warnings while testing
=head1 SYNOPSIS
For scripts that have no plan
use Test::NoWarnings;
that's it, you don't need to do anything else
For scripts that look like
use Test::More tests => x;
change to
use Test::More tests => x + 1;
use Test::NoWarnings;
=head1 DESCRIPTION
In general, your tests shouldn't produce warnings. This modules causes any
warnings to be captured and stored. It automatically adds an extra test that
will run when your script ends to check that there were no warnings. If
there were any warings, the test will give a "not ok" and diagnostics of
where, when and what the warning was, including a stack trace of what was
going on when the it occurred.
If some of your tests B<are supposed to> produce warnings then you should be
capturing and checking them with L<Test::Warn>, that way L<Test::NoWarnings>
will not see them and so not complain.
The test is run by an END block in Test::NoWarnings. It will not be run when
any forked children exit.
=head1 USAGE
Simply by using the module, you automatically get an extra test at the end
of your script that checks that no warnings were emitted. So just stick
use Test::NoWarnings
at the top of your script and continue as normal.
If you want more control you can invoke the test manually at any time with
C<had_no_warnings()>.
The warnings your test has generated so far are stored in an array. You can
look inside and clear this whenever you want with C<warnings()> and
C<clear_warnings()>, however, if you are doing this sort of thing then you
probably want to use L<Test::Warn> in combination with L<Test::NoWarnings>.
=head1 USE vs REQUIRE
You will almost always want to do
use Test::NoWarnings
If you do a C<require> rather than a C<use>, then there will be no automatic
test at the end of your script.
=head1 OUTPUT
If warning is captured during your test then the details will output as part
of the diagnostics. You will get:
=over 2
=item o
the number and name of the test that was executed just before the warning
(if no test had been executed these will be 0 and '')
=item o
the message passed to C<warn>,
=item o
a full dump of the stack when warn was called, courtesy of the C<Carp>
module
=back
=head1 EXPORTABLE FUNCTIONS
=head2 had_no_warnings
This checks that there have been warnings emitted by your test scripts.
Usually you will not call this explicitly as it is called automatically when
your script finishes.
=head2 clear_warnings
This will clear the array of warnings that have been captured. If the array
is empty then a call to C<had_no_warnings()> will produce a pass result.
=head2 warnings
This will return the array of warnings captured so far. Each element of this
array is an object containing information about the warning. The following
methods are available on these object.
=over 2
=item *
$warn-E<gt>getMessage
Get the message that would been printed by the warning.
=item *
$warn-E<gt>getCarp
Get a stack trace of what was going on when the warning happened, this stack
trace is just a string generated by the L<Carp> module.
=item *
$warn-E<gt>getTrace
Get a stack trace object generated by the L<Devel::StackTrace> module. This
will return undef if L<Devel::StackTrace> is not installed.
=item *
$warn-E<gt>getTest
Get the number of the test that executed before the warning was emitted.
=item *
$warn-E<gt>getTestName
Get the name of the test that executed before the warning was emitted.
=back
=head1 PITFALLS
When counting your tests for the plan, don't forget to include the test that
runs automatically when your script ends.
=head1 SUPPORT
Bugs should be reported via the CPAN bug tracker at
L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-NoWarnings>
For other issues, contact the author.
=head1 HISTORY
This was previously known as L<Test::Warn::None>
=head1 SEE ALSO
L<Test::Builder>, L<Test::Warn>
=head1 AUTHORS
Fergal Daly E<lt>fergal@esatclear.ieE<gt>
Adam Kennedy E<lt>adamk@cpan.orgE<gt>
=head1 COPYRIGHT
Copyright 2003 - 2007 Fergal Daly.
Some parts copyright 2010 Adam Kennedy.
This program is free software and comes with no warranty. It is distributed
under the LGPL license
See the file F<LGPL> included in this distribution or
F<http://www.fsf.org/licenses/licenses.html>.
=cut

View file

@ -1,78 +0,0 @@
package Test::NoWarnings::Warning;
use 5.006;
use strict;
use Carp ();
use vars qw{$VERSION};
BEGIN {
$VERSION = '1.02';
# Optional stacktrace support
eval "require Devel::StackTrace";
}
sub new {
my $class = shift;
bless { @_ }, $class;
}
sub getTrace {
$_[0]->{Trace};
}
sub fillTrace {
my $self = shift;
$self->{Trace} = Devel::StackTrace->new(
ignore_class => [__PACKAGE__, @_],
) if $Devel::StackTrace::VERSION;
}
sub getCarp {
$_[0]->{Carp};
}
sub fillCarp {
my $self = shift;
my $msg = shift;
$Carp::Internal{ __PACKAGE__ . "" }++;
local $Carp::CarpLevel = $Carp::CarpLevel + 1;
$self->{Carp} = Carp::longmess($msg);
$Carp::Internal{ __PACKAGE__ . "" }--;
}
sub getMessage {
$_[0]->{Message};
}
sub setMessage {
$_[0]->{Message} = $_[1];
}
sub fillTest {
my $self = shift;
my $builder = shift;
my $prev_test = $builder->current_test;
$self->{Test} = $prev_test;
my @tests = $builder->details;
my $prev_test_name = $prev_test ? $tests[$prev_test - 1]->{name} : "";
$self->{TestName} = $prev_test_name;
}
sub getTest {
$_[0]->{Test};
}
sub getTestName {
$_[0]->{TestName};
}
sub toString {
my $self = shift;
return <<EOM;
Previous test $self->{Test} '$self->{TestName}'
$self->{Carp}
EOM
}
1;

View file

@ -3,10 +3,9 @@ package DBD::SQLite;
use 5.006;
use strict;
use DBI 1.57 ();
use DynaLoader ();
use XSLoader ();
our $VERSION = '1.56';
our @ISA = 'DynaLoader';
our $VERSION = '1.76';
# sqlite_version cache (set in the XS bootstrap)
our ($sqlite_version, $sqlite_version_number);
@ -14,7 +13,7 @@ our ($sqlite_version, $sqlite_version_number);
# not sure if we still need these...
our ($err, $errstr);
__PACKAGE__->bootstrap($VERSION);
XSLoader::load('DBD::SQLite', $VERSION);
# New or old API?
use constant NEWAPI => ($DBI::VERSION >= 1.608);
@ -47,6 +46,8 @@ sub driver {
DBD::SQLite::db->install_method('sqlite_set_authorizer');
DBD::SQLite::db->install_method('sqlite_backup_from_file');
DBD::SQLite::db->install_method('sqlite_backup_to_file');
DBD::SQLite::db->install_method('sqlite_backup_from_dbh');
DBD::SQLite::db->install_method('sqlite_backup_to_dbh');
DBD::SQLite::db->install_method('sqlite_enable_load_extension');
DBD::SQLite::db->install_method('sqlite_load_extension');
DBD::SQLite::db->install_method('sqlite_register_fts3_perl_tokenizer');
@ -57,6 +58,11 @@ sub driver {
DBD::SQLite::db->install_method('sqlite_db_status', { O => 0x0004 });
DBD::SQLite::st->install_method('sqlite_st_status', { O => 0x0004 });
DBD::SQLite::db->install_method('sqlite_create_module');
DBD::SQLite::db->install_method('sqlite_limit');
DBD::SQLite::db->install_method('sqlite_db_config');
DBD::SQLite::db->install_method('sqlite_get_autocommit');
DBD::SQLite::db->install_method('sqlite_txn_state');
DBD::SQLite::db->install_method('sqlite_error_offset');
$methods_are_installed++;
}
@ -180,7 +186,7 @@ sub install_collation {
# default implementation for sqlite 'REGEXP' infix operator.
# Note : args are reversed, i.e. "a REGEXP b" calls REGEXP(b, a)
# (see http://www.sqlite.org/vtab.html#xfindfunction)
# (see https://www.sqlite.org/vtab.html#xfindfunction)
sub regexp {
use locale;
return if !defined $_[0] || !defined $_[1];
@ -190,6 +196,8 @@ sub regexp {
package # hide from PAUSE
DBD::SQLite::db;
use DBI qw/:sql_types/;
sub prepare {
my $dbh = shift;
my $sql = shift;
@ -245,19 +253,26 @@ sub ping {
return $dbh->FETCH('Active') ? 1 : 0;
}
sub _get_version {
return ( DBD::SQLite::db::FETCH($_[0], 'sqlite_version') );
sub quote {
my ($self, $value, $data_type) = @_;
return "NULL" unless defined $value;
if (defined $data_type and (
$data_type == DBI::SQL_BIT ||
$data_type == DBI::SQL_BLOB ||
$data_type == DBI::SQL_BINARY ||
$data_type == DBI::SQL_VARBINARY ||
$data_type == DBI::SQL_LONGVARBINARY)) {
return q(X') . unpack('H*', $value) . q(');
}
$value =~ s/'/''/g;
return "'$value'";
}
my %info = (
17 => 'SQLite', # SQL_DBMS_NAME
18 => \&_get_version, # SQL_DBMS_VER
29 => '"', # SQL_IDENTIFIER_QUOTE_CHAR
);
sub get_info {
my ($dbh, $info_type) = @_;
my $v = $info{int($info_type)};
require DBD::SQLite::GetInfo;
my $v = $DBD::SQLite::GetInfo::info{int($info_type)};
$v = $v->($dbh) if ref $v eq 'CODE';
return $v;
}
@ -553,6 +568,15 @@ my @FOREIGN_KEY_INFO_SQL_CLI = qw(
UNIQUE_OR_PRIMARY
);
my $DEFERRABLE_RE = qr/
(?:(?:
on \s+ (?:delete|update) \s+ (?:set \s+ null|set \s+ default|cascade|restrict|no \s+ action)
|
match \s* (?:\S+|".+?(?<!")")
) \s*)*
((?:not)? \s* deferrable (?: \s* initially \s* (?: immediate | deferred))?)?
/sxi;
sub foreign_key_info {
my ($dbh, $pk_catalog, $pk_schema, $pk_table, $fk_catalog, $fk_schema, $fk_table) = @_;
@ -570,9 +594,11 @@ sub foreign_key_info {
($dbname eq 'temp') ? 'sqlite_temp_master' :
$quoted_dbname.'.sqlite_master';
my $tables = $dbh->selectall_arrayref("SELECT name FROM $master_table WHERE type = ?", undef, "table") or return;
my $tables = $dbh->selectall_arrayref("SELECT name, sql FROM $master_table WHERE type = ?", undef, "table") or return;
for my $table (@$tables) {
my $tbname = $table->[0];
my $ddl = $table->[1];
my (@rels, %relid2rels);
next if defined $fk_table && $fk_table ne '%' && $fk_table ne $tbname;
my $quoted_tbname = $dbh->quote_identifier($tbname);
@ -603,7 +629,17 @@ sub foreign_key_info {
next if defined $pk_schema && $pk_schema ne '%' && $pk_schema ne $table_info{$row->{table}}{schema};
push @fk_info, {
# cribbed from DBIx::Class::Schema::Loader::DBI::SQLite
my $rel = $rels[ $row->{id} ] ||= {
local_columns => [],
remote_columns => undef,
remote_table => $row->{table},
};
push @{ $rel->{local_columns} }, $row->{from};
push @{ $rel->{remote_columns} }, $row->{to}
if defined $row->{to};
my $fk_row = {
PKTABLE_CAT => undef,
PKTABLE_SCHEM => $table_info{$row->{table}}{schema},
PKTABLE_NAME => $row->{table},
@ -620,6 +656,44 @@ sub foreign_key_info {
DEFERRABILITY => undef,
UNIQUE_OR_PRIMARY => $table_info{$row->{table}}{columns}{$row->{to}} ? 'PRIMARY' : 'UNIQUE',
};
push @fk_info, $fk_row;
push @{ $relid2rels{$row->{id}} }, $fk_row; # keep so can fixup
}
# cribbed from DBIx::Class::Schema::Loader::DBI::SQLite
# but with additional parsing of which kind of deferrable
REL: for my $relid (keys %relid2rels) {
my $rel = $rels[$relid];
my $deferrable = $DBI_code_for_rule{'NOT DEFERRABLE'};
my $local_cols = '"?' . (join '"? \s* , \s* "?', map quotemeta, @{ $rel->{local_columns} }) . '"?';
my $remote_cols = '"?' . (join '"? \s* , \s* "?', map quotemeta, @{ $rel->{remote_columns} || [] }) . '"?';
my ($deferrable_clause) = $ddl =~ /
foreign \s+ key \s* \( \s* $local_cols \s* \) \s* references \s* (?:\S+|".+?(?<!")") \s*
(?:\( \s* $remote_cols \s* \) \s*)?
$DEFERRABLE_RE
/sxi;
if (!$deferrable_clause) {
# check for inline constraint if 1 local column
if (@{ $rel->{local_columns} } == 1) {
my ($local_col) = @{ $rel->{local_columns} };
my ($remote_col) = @{ $rel->{remote_columns} || [] };
$remote_col ||= '';
($deferrable_clause) = $ddl =~ /
"?\Q$local_col\E"? \s* (?:\w+\s*)* (?: \( \s* \d\+ (?:\s*,\s*\d+)* \s* \) )? \s*
references \s+ (?:\S+|".+?(?<!")") (?:\s* \( \s* "?\Q$remote_col\E"? \s* \))? \s*
$DEFERRABLE_RE
/sxi;
}
}
if ($deferrable_clause) {
# default is already NOT
if ($deferrable_clause !~ /not/i) {
$deferrable = $deferrable_clause =~ /deferred/i
? $DBI_code_for_rule{'INITIALLY DEFERRED'}
: $DBI_code_for_rule{'INITIALLY IMMEDIATE'};
}
}
$_->{DEFERRABILITY} = $deferrable for @{ $relid2rels{$relid} };
}
}
}
@ -694,7 +768,7 @@ sub statistics_info {
NON_UNIQUE => $row->{unique} ? 0 : 1,
INDEX_QUALIFIER => undef,
INDEX_NAME => $row->{name},
TYPE => 'btree', # see http://www.sqlite.org/version3.html esp. "Traditional B-trees are still used for indices"
TYPE => 'btree', # see https://www.sqlite.org/version3.html esp. "Traditional B-trees are still used for indices"
ORDINAL_POSITION => $info->{seqno} + 1,
COLUMN_NAME => $info->{name},
ASC_OR_DESC => undef,
@ -721,45 +795,68 @@ sub statistics_info {
return $sponge_sth;
}
my @TypeInfoKeys = qw/
TYPE_NAME
DATA_TYPE
COLUMN_SIZE
LITERAL_PREFIX
LITERAL_SUFFIX
CREATE_PARAMS
NULLABLE
CASE_SENSITIVE
SEARCHABLE
UNSIGNED_ATTRIBUTE
FIXED_PREC_SCALE
AUTO_UNIQUE_VALUE
LOCAL_TYPE_NAME
MINIMUM_SCALE
MAXIMUM_SCALE
SQL_DATA_TYPE
SQL_DATETIME_SUB
NUM_PREC_RADIX
INTERVAL_PRECISION
/;
my %TypeInfo = (
SQL_INTEGER ,=> {
TYPE_NAME => 'INTEGER',
DATA_TYPE => SQL_INTEGER,
NULLABLE => 2, # no for integer primary key, otherwise yes
SEARCHABLE => 3,
},
SQL_DOUBLE ,=> {
TYPE_NAME => 'REAL',
DATA_TYPE => SQL_DOUBLE,
NULLABLE => 1,
SEARCHABLE => 3,
},
SQL_VARCHAR ,=> {
TYPE_NAME => 'TEXT',
DATA_TYPE => SQL_VARCHAR,
LITERAL_PREFIX => "'",
LITERAL_SUFFIX => "'",
NULLABLE => 1,
SEARCHABLE => 3,
},
SQL_BLOB ,=> {
TYPE_NAME => 'BLOB',
DATA_TYPE => SQL_BLOB,
NULLABLE => 1,
SEARCHABLE => 3,
},
SQL_UNKNOWN_TYPE ,=> {
DATA_TYPE => SQL_UNKNOWN_TYPE,
},
);
sub type_info_all {
return; # XXX code just copied from DBD::Oracle, not yet thought about
# return [
# {
# TYPE_NAME => 0,
# DATA_TYPE => 1,
# COLUMN_SIZE => 2,
# LITERAL_PREFIX => 3,
# LITERAL_SUFFIX => 4,
# CREATE_PARAMS => 5,
# NULLABLE => 6,
# CASE_SENSITIVE => 7,
# SEARCHABLE => 8,
# UNSIGNED_ATTRIBUTE => 9,
# FIXED_PREC_SCALE => 10,
# AUTO_UNIQUE_VALUE => 11,
# LOCAL_TYPE_NAME => 12,
# MINIMUM_SCALE => 13,
# MAXIMUM_SCALE => 14,
# SQL_DATA_TYPE => 15,
# SQL_DATETIME_SUB => 16,
# NUM_PREC_RADIX => 17,
# },
# [ 'CHAR', 1, 255, '\'', '\'', 'max length', 1, 1, 3,
# undef, '0', '0', undef, undef, undef, 1, undef, undef
# ],
# [ 'NUMBER', 3, 38, undef, undef, 'precision,scale', 1, '0', 3,
# '0', '0', '0', undef, '0', 38, 3, undef, 10
# ],
# [ 'DOUBLE', 8, 15, undef, undef, undef, 1, '0', 3,
# '0', '0', '0', undef, undef, undef, 8, undef, 10
# ],
# [ 'DATE', 9, 19, '\'', '\'', undef, 1, '0', 3,
# undef, '0', '0', undef, '0', '0', 11, undef, undef
# ],
# [ 'VARCHAR', 12, 1024*1024, '\'', '\'', 'max length', 1, 1, 3,
# undef, '0', '0', undef, undef, undef, 12, undef, undef
# ]
# ];
my $idx = 0;
my @info = ({map {$_ => $idx++} @TypeInfoKeys});
for my $id (sort {$a <=> $b} keys %TypeInfo) {
push @info, [map {$TypeInfo{$id}{$_}} @TypeInfoKeys];
}
return \@info;
}
my @COLUMN_INFO = qw(
@ -936,7 +1033,7 @@ DBD::SQLite - Self-contained RDBMS in a DBI Driver
=head1 DESCRIPTION
SQLite is a public domain file-based relational database engine that
you can find at L<http://www.sqlite.org/>.
you can find at L<https://www.sqlite.org/>.
B<DBD::SQLite> is a Perl DBI driver for SQLite, that includes
the entire thing in the distribution.
@ -950,7 +1047,7 @@ SQLite supports the following features:
=item Implements a large subset of SQL92
See L<http://www.sqlite.org/lang.html> for details.
See L<https://www.sqlite.org/lang.html> for details.
=item A complete DB in a single disk file
@ -977,7 +1074,7 @@ are limited by the typeless nature of the SQLite database.
=head1 SQLITE VERSION
DBD::SQLite is usually compiled with a bundled SQLite library
(SQLite version S<3.22.0> as of this release) for consistency.
(SQLite version S<3.46.1> as of this release) for consistency.
However, a different version of SQLite may sometimes be used for
some reasons like security, or some new experimental features.
@ -1021,7 +1118,7 @@ If the filename C<$dbfile> is an empty string, then a private,
temporary on-disk database will be created. This private database will
be automatically deleted as soon as the database connection is closed.
As of 1.41_01, you can pass URI filename (see L<http://www.sqlite.org/uri.html>)
As of 1.41_01, you can pass URI filename (see L<https://www.sqlite.org/uri.html>)
as well for finer control:
my $dbh = DBI->connect("dbi:SQLite:uri=file:$path_to_dbfile?mode=rwc");
@ -1038,7 +1135,7 @@ You can set sqlite_open_flags (only) when you connect to a database:
sqlite_open_flags => SQLITE_OPEN_READONLY,
});
See L<http://www.sqlite.org/c3ref/open.html> for details.
See L<https://www.sqlite.org/c3ref/open.html> for details.
As of 1.49_05, you can also make a database read-only by setting
C<ReadOnly> attribute to true (only) when you connect to a database.
@ -1156,7 +1253,7 @@ like this while executing:
SELECT bar FROM foo GROUP BY bar HAVING count(*) > "5";
There are three workarounds for this.
There are four workarounds for this.
=over 4
@ -1182,6 +1279,15 @@ This is somewhat weird, but works anyway.
});
$sth->execute(5);
=item Use SQL cast() function
This is more explicit way to do the above.
my $sth = $dbh->prepare(q{
SELECT bar FROM foo GROUP BY bar HAVING count(*) > cast(? as integer);
});
$sth->execute(5);
=item Set C<sqlite_see_if_its_a_number> database handle attribute
As of version 1.32_02, you can use C<sqlite_see_if_its_a_number>
@ -1230,7 +1336,7 @@ SQLite supports several placeholder expressions, including C<?>
and C<:AAAA>. Consult the L<DBI> and SQLite documentation for
details.
L<http://www.sqlite.org/lang_expr.html#varparam>
L<https://www.sqlite.org/lang_expr.html#varparam>
Note that a question mark actually means a next unused (numbered)
placeholder. You're advised not to use it with other (numbered or
@ -1300,7 +1406,7 @@ in the worst case. See also L</"Performance"> section below.
=back
See L<http://www.sqlite.org/pragma.html> for more details.
See L<https://www.sqlite.org/pragma.html> for more details.
=head2 Foreign Keys
@ -1328,7 +1434,7 @@ SQLite, be prepared, and please do extensive testing to ensure
that your applications will continue to work when the foreign keys
support is enabled by default.
See L<http://www.sqlite.org/foreignkeys.html> for details.
See L<https://www.sqlite.org/foreignkeys.html> for details.
=head2 Transactions
@ -1382,7 +1488,7 @@ automatically begin if you execute another statement.
This C<AutoCommit> mode is independent from the autocommit mode
of the internal SQLite library, which always begins by a C<BEGIN>
statement, and ends by a C<COMMIT> or a <ROLLBACK>.
statement, and ends by a C<COMMIT> or a C<ROLLBACK>.
=head2 Transaction and Database Locking
@ -1451,9 +1557,22 @@ of the rest (since 1.30_01, and without creating DBI's statement
handles internally since 1.47_01). If you do need to use C<prepare>
or C<prepare_cached> (which I don't recommend in this case, because
typically there's no placeholder nor reusable part in a dump),
you can look at << $sth->{sqlite_unprepared_statements} >> to retrieve
you can look at C<< $sth->{sqlite_unprepared_statements} >> to retrieve
what's left, though it usually contains nothing but white spaces.
=head2 TYPE statement attribute
Because of historical reasons, DBD::SQLite's C<TYPE> statement
handle attribute returns an array ref of string values, contrary to
the DBI specification. This value is also less useful for SQLite
users because SQLite uses dynamic type system (that means,
the datatype of a value is associated with the value itself, not
with its container).
As of version 1.61_02, if you set C<sqlite_prefer_numeric_type>
database handle attribute to true, C<TYPE> statement handle
attribute returns an array of integer, as an experiment.
=head2 Performance
SQLite is fast, very fast. Matt processed his 72MB log file with it,
@ -1502,24 +1621,42 @@ Your sweet spot probably lies somewhere in between.
=item sqlite_version
Returns the version of the SQLite library which B<DBD::SQLite> is using,
e.g., "2.8.0". Can only be read.
e.g., "3.26.0". Can only be read.
=item sqlite_unicode
=item sqlite_string_mode
If set to a true value, B<DBD::SQLite> will turn the UTF-8 flag on for all
text strings coming out of the database (this feature is currently disabled
for perl < 5.8.5). For more details on the UTF-8 flag see
L<perlunicode>. The default is for the UTF-8 flag to be turned off.
SQLite strings are simple arrays of bytes, but Perl strings can store any
arbitrary Unicode code point. Thus, DBD::SQLite has to adopt some method
of translating between those two models. This parameter defines that
translation.
Also note that due to some bizarreness in SQLite's type system (see
L<http://www.sqlite.org/datatype3.html>), if you want to retain
blob-style behavior for B<some> columns under C<< $dbh->{sqlite_unicode} = 1
>> (say, to store images in the database), you have to state so
Accepted values are the following constants:
=over
=item * DBD_SQLITE_STRING_MODE_BYTES: All strings are assumed to
represent bytes. A Perl string that contains any code point above 255
will trigger an exception. This is appropriate for Latin-1 strings,
binary data, pre-encoded UTF-8 strings, etc.
=item * DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK: All Perl strings are encoded
to UTF-8 before being given to SQLite. Perl will B<try> to decode SQLite
strings as UTF-8 when giving them to Perl. Should any such string not be
valid UTF-8, a warning is thrown, and the string is left undecoded.
This is appropriate for strings that are decoded to characters via,
e.g., L<Encode/decode>.
Also note that, due to some bizarreness in SQLite's type system (see
L<https://www.sqlite.org/datatype3.html>), if you want to retain
blob-style behavior for B<some> columns under DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK
(say, to store images in the database), you have to state so
explicitly using the 3-argument form of L<DBI/bind_param> when doing
updates:
use DBI qw(:sql_types);
$dbh->{sqlite_unicode} = 1;
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
$dbh->{sqlite_string_mode} = DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK;
my $sth = $dbh->prepare("INSERT INTO mytable (blobcolumn) VALUES (?)");
# Binary_data will be stored as is.
@ -1527,9 +1664,31 @@ updates:
Defining the column type as C<BLOB> in the DDL is B<not> sufficient.
This attribute was originally named as C<unicode>, and renamed to
C<sqlite_unicode> for integrity since version 1.26_06. Old C<unicode>
attribute is still accessible but will be deprecated in the near future.
=item * DBD_SQLITE_STRING_MODE_UNICODE_STRICT: Like
DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK but usually throws an exception
rather than a warning if SQLite sends invalid UTF-8. (In Perl callbacks
from SQLite we still warn instead.)
=item * DBD_SQLITE_STRING_MODE_UNICODE_NAIVE: Like
DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK but uses a "naïve" UTF-8 decoding
method that forgoes validation. This is marginally faster than a validated
decode, but it can also B<corrupt> B<Perl> B<itself!>
=item * DBD_SQLITE_STRING_MODE_PV (default, but B<DO> B<NOT> B<USE>): Like
DBD_SQLITE_STRING_MODE_BYTES, but when translating Perl strings to SQLite
the Perl string's internal byte buffer is given to SQLite. B<This> B<is>
B<bad>, but it's been the default for many years, and changing that would
break existing applications.
=back
=item C<sqlite_unicode> or C<unicode> (deprecated)
If truthy, equivalent to setting C<sqlite_string_mode> to
DBD_SQLITE_STRING_MODE_UNICODE_NAIVE; if falsy, equivalent to
DBD_SQLITE_STRING_MODE_PV.
Prefer C<sqlite_string_mode> in all new code.
=item sqlite_allow_multiple_statements
@ -1556,7 +1715,12 @@ for details.
=item sqlite_extended_result_codes
If set to true, DBD::SQLite uses extended result codes where appropriate
(see L<http://www.sqlite.org/rescode.html>).
(see L<https://www.sqlite.org/rescode.html>).
=item sqlite_defensive
If set to true, language features that allow ordinary SQL to deliberately
corrupt the database file are prohibited.
=back
@ -1585,7 +1749,8 @@ Returns all tables and schemas (databases) as specified in L<DBI/table_info>.
The schema and table arguments will do a C<LIKE> search. You can specify an
ESCAPE character by including an 'Escape' attribute in \%attr. The C<$type>
argument accepts a comma separated list of the following types 'TABLE',
'VIEW', 'LOCAL TEMPORARY' and 'SYSTEM TABLE' (by default all are returned).
'INDEX', 'VIEW', 'TRIGGER', 'LOCAL TEMPORARY' and 'SYSTEM TABLE'
(by default all are returned).
Note that a statement handle is returned, and not a direct list of tables.
The following fields are returned:
@ -1598,8 +1763,8 @@ databases will be in the name given when the database was attached.
B<TABLE_NAME>: The name of the table or view.
B<TABLE_TYPE>: The type of object returned. Will be one of 'TABLE', 'VIEW',
'LOCAL TEMPORARY' or 'SYSTEM TABLE'.
B<TABLE_TYPE>: The type of object returned. Will be one of 'TABLE', 'INDEX',
'VIEW', 'TRIGGER', 'LOCAL TEMPORARY' or 'SYSTEM TABLE'.
=head2 primary_key, primary_key_info
@ -1665,10 +1830,12 @@ B<DELETE_RULE>:
The referential action for the DELETE rule.
The codes are the same as for UPDATE_RULE.
Unfortunately, the B<DEFERRABILITY> field is always C<undef>;
as a matter of fact, deferrability clauses are supported by SQLite,
but they can't be reported because the C<PRAGMA foreign_key_list>
tells nothing about them.
B<DEFERRABILITY>:
The following codes are defined:
INITIALLY DEFERRED 5
INITIALLY IMMEDIATE 6
NOT DEFERRABLE 7
B<UNIQUE_OR_PRIMARY>:
Whether the column is primary or unique.
@ -1728,7 +1895,7 @@ returns true if the database file exists (or the database is in-memory), and the
The following methods can be called via the func() method with a little
tweak, but the use of func() method is now discouraged by the L<DBI> author
for various reasons (see DBI's document
L<http://search.cpan.org/dist/DBI/lib/DBI/DBD.pm#Using_install_method()_to_expose_driver-private_methods>
L<https://metacpan.org/pod/DBI::DBD#Using-install_method()-to-expose-driver-private-methods>
for details). So, if you're using L<DBI> >= 1.608, use these C<sqlite_>
methods. If you need to use an older L<DBI>, you can call these like this:
@ -1755,7 +1922,8 @@ C<$dbh-E<gt>sqlite_last_insert_rowid()> directly.
=head2 $dbh->sqlite_db_filename()
Retrieve the current (main) database filename. If the database is in-memory or temporary, this returns C<undef>.
Retrieve the current (main) database filename. If the database is in-memory
or temporary, this returns an empty string, or C<undef>.
=head2 $dbh->sqlite_busy_timeout()
@ -1801,6 +1969,13 @@ After this, it could be used from SQL as:
INSERT INTO mytable ( now() );
The function should return a scalar value, and the value is treated as a text
(or a number if appropriate) by default. If you do need to specify a type
of the return value (like BLOB), you can return a reference to an array that
contains the value and the type, as of 1.65_01.
$dbh->sqlite_create_function( 'md5', 1, sub { return [md5($_[0]), SQL_BLOB] } );
=head3 REGEXP function
SQLite includes syntactic support for an infix operator 'REGEXP', but
@ -2105,18 +2280,39 @@ special :memory: database, and you wish to populate it from an existing DB.
This method accesses the SQLite Online Backup API, and will take a backup of
the currently connected database, and write it out to the named file.
=head2 $dbh->sqlite_backup_from_dbh( $another_dbh )
This method accesses the SQLite Online Backup API, and will take a backup of
the database for the passed handle, copying it to, and overwriting, your current database
connection. This can be particularly handy if your current connection is to the
special :memory: database, and you wish to populate it from an existing DB.
You can use this to backup from an in-memory database to another in-memory database.
=head2 $dbh->sqlite_backup_to_dbh( $another_dbh )
This method accesses the SQLite Online Backup API, and will take a backup of
the currently connected database, and write it out to the passed database handle.
=head2 $dbh->sqlite_enable_load_extension( $bool )
Calling this method with a true value enables loading (external)
SQLite3 extensions. After the call, you can load extensions like this:
$dbh->sqlite_enable_load_extension(1);
$sth = $dbh->prepare("select load_extension('libsqlitefunctions.so')")
$sth = $dbh->prepare("select load_extension('libmemvfs.so')")
or die "Cannot prepare: " . $dbh->errstr();
=head2 $dbh->sqlite_load_extension( $file, $proc )
Loading an extension by a select statement (with the "load_extension" SQLite3 function like above) has some limitations. If you need to, say, create other functions from an extension, use this method. $file (a path to the extension) is mandatory, and $proc (an entry point name) is optional. You need to call C<sqlite_enable_load_extension> before calling C<sqlite_load_extension>.
Loading an extension by a select statement (with the "load_extension" SQLite3 function like above) has some limitations. If the extension you want to use creates other functions that are not native to SQLite, use this method instead. $file (a path to the extension) is mandatory, and $proc (an entry point name) is optional. You need to call C<sqlite_enable_load_extension> before calling C<sqlite_load_extension>:
$dbh->sqlite_enable_load_extension(1);
$dbh->sqlite_load_extension('libsqlitefunctions.so')
or die "Cannot load extension: " . $dbh->errstr();
If the extension uses SQLite mutex functions like C<sqlite3_mutex_enter>, then
the extension should be compiled with the same C<SQLITE_THREADSAFE> compile-time
setting as this module, see C<DBD::SQLite::compile_options()>.
=head2 $dbh->sqlite_trace( $code_ref )
@ -2177,17 +2373,38 @@ is for internal use only.
=head2 $dbh->sqlite_db_status()
Returns a hash reference that holds a set of status information of database connection such as cache usage. See L<http://www.sqlite.org/c3ref/c_dbstatus_options.html> for details. You may also pass 0 as an argument to reset the status.
Returns a hash reference that holds a set of status information of database connection such as cache usage. See L<https://www.sqlite.org/c3ref/c_dbstatus_options.html> for details. You may also pass 0 as an argument to reset the status.
=head2 $sth->sqlite_st_status()
Returns a hash reference that holds a set of status information of SQLite statement handle such as full table scan count. See L<http://www.sqlite.org/c3ref/c_stmtstatus_counter.html> for details. Statement status only holds the current value.
Returns a hash reference that holds a set of status information of SQLite statement handle such as full table scan count. See L<https://www.sqlite.org/c3ref/c_stmtstatus_counter.html> for details. Statement status only holds the current value.
my $status = $sth->sqlite_st_status();
my $cur = $status->{fullscan_step};
You may also pass 0 as an argument to reset the status.
=head2 $dbh->sqlite_db_config( $id, $new_integer_value )
You can change how the connected database should behave like this:
use DBD::SQLite::Constants qw/:database_connection_configuration_options/;
my $dbh = DBI->connect('dbi:SQLite::memory:');
# This disables language features that allow ordinary SQL
# to deliberately corrupt the database file
$dbh->sqlite_db_config( SQLITE_DBCONFIG_DEFENSIVE, 1 );
# This disables two-arg version of fts3_tokenizer.
$dbh->sqlite_db_config( SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 0 );
C<sqlite_db_config> returns the new value after the call. If you just want to know the current value without changing anything, pass a negative integer value.
my $current_value = $dbh->sqlite_db_config( SQLITE_DBCONFIG_DEFENSIVE, -1 );
As of this writing, C<sqlite_db_config> only supports options that set an integer value. C<SQLITE_DBCONFIG_LOOKASIDE> and C<SQLITE_DBCONFIG_MAINDBNAME> are not supported. See also C<https://www.sqlite.org/capi3ref.html#sqlite3_db_config> for details.
=head2 $dbh->sqlite_create_module()
Registers a name for a I<virtual table module>. Module names must be
@ -2195,6 +2412,33 @@ registered before creating a new virtual table using the module and
before using a preexisting virtual table for the module.
Virtual tables are explained in L<DBD::SQLite::VirtualTable>.
=head2 $dbh->sqlite_limit( $category_id, $new_value )
Sets a new run-time limit for the category, and returns the current limit.
If the new value is a negative number (or omitted), the limit is unchanged
and just returns the current limit. Category ids (SQLITE_LIMIT_LENGTH,
SQLITE_LIMIT_VARIABLE_NUMBER, etc) can be imported from DBD::SQLite::Constants.
=head2 $dbh->sqlite_get_autocommit()
Returns true if the internal SQLite connection is in an autocommit mode.
This does not always return the same value as C<< $dbh->{AutoCommit} >>.
This returns false if you explicitly issue a C<<BEGIN>> statement.
=head2 $dbh->sqlite_txn_state()
Returns the internal transaction status of SQLite (not of DBI).
Return values (SQLITE_TXN_NONE, SQLITE_TXN_READ, SQLITE_TXN_WRITE)
can be imported from DBD::SQLite::Constants. You may pass an optional
schema name (usually "main"). If SQLite does not support this function,
or if you pass a wrong schema name, -1 is returned.
=head2 $dbh->sqlite_error_offset()
Returns the byte offset of the start of a problematic input SQL token
or -1 if the most recent error does not reference a specific token in
the input SQL (or DBD::SQLite is built with an older version of SQLite).
=head1 DRIVER FUNCTIONS
=head2 DBD::SQLite::compile_options()
@ -2205,7 +2449,7 @@ library is old or compiled with SQLITE_OMIT_COMPILEOPTION_DIAGS.
=head2 DBD::SQLite::sqlite_status()
Returns a hash reference that holds a set of status information of SQLite runtime such as memory usage or page cache usage (see L<http://www.sqlite.org/c3ref/c_status_malloc_count.html> for details). Each of the entry contains the current value and the highwater value.
Returns a hash reference that holds a set of status information of SQLite runtime such as memory usage or page cache usage (see L<https://www.sqlite.org/c3ref/c_status_malloc_count.html> for details). Each of the entry contains the current value and the highwater value.
my $status = DBD::SQLite::sqlite_status();
my $cur = $status->{memory_used}{current};
@ -2239,7 +2483,7 @@ DELETE operation would be written as follows :
The list of constants implemented in C<DBD::SQLite> is given
below; more information can be found ad
at L<http://www.sqlite.org/c3ref/constlist.html>.
at L<https://www.sqlite.org/c3ref/constlist.html>.
=head2 Authorizer Return Codes
@ -2299,7 +2543,7 @@ associated strings.
SQLite v3 provides the ability for users to supply arbitrary
comparison functions, known as user-defined "collation sequences" or
"collating functions", to be used for comparing two text values.
L<http://www.sqlite.org/datatype3.html#collation>
L<https://www.sqlite.org/datatype3.html#collation>
explains how collations are used in various SQL expressions.
=head2 Builtin collation sequences
@ -2357,18 +2601,17 @@ or
=head2 Unicode handling
If the attribute C<< $dbh->{sqlite_unicode} >> is set, strings coming from
the database and passed to the collation function will be properly
tagged with the utf8 flag; but this only works if the
C<sqlite_unicode> attribute is set B<before> the first call to
a perl collation sequence . The recommended way to activate unicode
is to set the parameter at connection time :
Depending on the C<< $dbh->{sqlite_string_mode} >> value, strings coming
from the database and passed to the collation function may be decoded as
UTF-8. This only works, though, if the C<sqlite_string_mode> attribute is
set B<before> the first call to a perl collation sequence. The recommended
way to activate unicode is to set C<sqlite_string_mode> at connection time:
my $dbh = DBI->connect(
"dbi:SQLite:dbname=foo", "", "",
{
RaiseError => 1,
sqlite_unicode => 1,
sqlite_string_mode => DBD_SQLITE_STRING_MODE_UNICODE_STRICT,
}
);
@ -2390,7 +2633,7 @@ characters :
use DBD::SQLite;
$DBD::SQLite::COLLATION{no_accents} = sub {
my ( $a, $b ) = map lc, @_;
tr[àâáäåãçðèêéëìîíïñòôóöõøùûúüý]
tr[àâáäåãçðèêéëìîíïñòôóöõøùûúüý]
[aaaaaacdeeeeiiiinoooooouuuuy] for $a, $b;
$a cmp $b;
};
@ -2463,7 +2706,7 @@ then query which buildings overlap or are contained within a specified region:
$minLong, $maxLong, $minLat, $maxLat);
For more detail, please see the SQLite R-Tree page
(L<http://www.sqlite.org/rtree.html>). Note that custom R-Tree
(L<https://www.sqlite.org/rtree.html>). Note that custom R-Tree
queries using callbacks, as mentioned in the prior link, have not been
implemented yet.
@ -2547,13 +2790,17 @@ Reading/writing into blobs using C<sqlite2_blob_open> / C<sqlite2_blob_close>.
=head2 Support for custom callbacks for R-Tree queries
Custom queries of a R-Tree index using a callback are possible with
the SQLite C API (L<http://www.sqlite.org/rtree.html>), so one could
the SQLite C API (L<https://www.sqlite.org/rtree.html>), so one could
potentially use a callback that narrowed the result set down based
on a specific need, such as querying for overlapping circles.
=head1 SUPPORT
Bugs should be reported via the CPAN bug tracker at
Bugs should be reported to GitHub issues:
L<https://github.com/DBD-SQLite/DBD-SQLite/issues>
or via RT if you prefer:
L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=DBD-SQLite>

View file

@ -8,6 +8,18 @@ use warnings;
use base 'Exporter';
use DBD::SQLite;
our @EXPORT_OK = (
'DBD_SQLITE_STRING_MODE_PV',
'DBD_SQLITE_STRING_MODE_BYTES',
'DBD_SQLITE_STRING_MODE_UNICODE_NAIVE',
'DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK',
'DBD_SQLITE_STRING_MODE_UNICODE_STRICT',
# allowed_return_values_from_sqlite3_txn_state
qw/
SQLITE_TXN_NONE
SQLITE_TXN_READ
SQLITE_TXN_WRITE
/,
# authorizer_action_codes
qw/
SQLITE_ALTER_TABLE
@ -57,27 +69,62 @@ our @EXPORT_OK = (
SQLITE_VERSION_NUMBER
/,
# database_connection_configuration_options
qw/
SQLITE_DBCONFIG_DEFENSIVE
SQLITE_DBCONFIG_DQS_DDL
SQLITE_DBCONFIG_DQS_DML
SQLITE_DBCONFIG_ENABLE_FKEY
SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
SQLITE_DBCONFIG_ENABLE_QPSG
SQLITE_DBCONFIG_ENABLE_TRIGGER
SQLITE_DBCONFIG_ENABLE_VIEW
SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
SQLITE_DBCONFIG_LOOKASIDE
SQLITE_DBCONFIG_MAINDBNAME
SQLITE_DBCONFIG_MAX
SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
SQLITE_DBCONFIG_RESET_DATABASE
SQLITE_DBCONFIG_REVERSE_SCANORDER
SQLITE_DBCONFIG_STMT_SCANSTATUS
SQLITE_DBCONFIG_TRIGGER_EQP
SQLITE_DBCONFIG_TRUSTED_SCHEMA
SQLITE_DBCONFIG_WRITABLE_SCHEMA
/,
# extended_result_codes
qw/
SQLITE_ABORT_ROLLBACK
SQLITE_AUTH_USER
SQLITE_BUSY_RECOVERY
SQLITE_BUSY_SNAPSHOT
SQLITE_BUSY_TIMEOUT
SQLITE_CANTOPEN_CONVPATH
SQLITE_CANTOPEN_DIRTYWAL
SQLITE_CANTOPEN_FULLPATH
SQLITE_CANTOPEN_ISDIR
SQLITE_CANTOPEN_NOTEMPDIR
SQLITE_CANTOPEN_SYMLINK
SQLITE_CONSTRAINT_CHECK
SQLITE_CONSTRAINT_COMMITHOOK
SQLITE_CONSTRAINT_DATATYPE
SQLITE_CONSTRAINT_FOREIGNKEY
SQLITE_CONSTRAINT_FUNCTION
SQLITE_CONSTRAINT_NOTNULL
SQLITE_CONSTRAINT_PINNED
SQLITE_CONSTRAINT_PRIMARYKEY
SQLITE_CONSTRAINT_ROWID
SQLITE_CONSTRAINT_TRIGGER
SQLITE_CONSTRAINT_UNIQUE
SQLITE_CONSTRAINT_VTAB
SQLITE_CORRUPT_INDEX
SQLITE_CORRUPT_SEQUENCE
SQLITE_CORRUPT_VTAB
SQLITE_ERROR_MISSING_COLLSEQ
SQLITE_ERROR_RETRY
SQLITE_ERROR_SNAPSHOT
SQLITE_IOERR_ACCESS
SQLITE_IOERR_AUTH
SQLITE_IOERR_BEGIN_ATOMIC
@ -86,6 +133,8 @@ our @EXPORT_OK = (
SQLITE_IOERR_CLOSE
SQLITE_IOERR_COMMIT_ATOMIC
SQLITE_IOERR_CONVPATH
SQLITE_IOERR_CORRUPTFS
SQLITE_IOERR_DATA
SQLITE_IOERR_DELETE
SQLITE_IOERR_DELETE_NOENT
SQLITE_IOERR_DIR_CLOSE
@ -93,6 +142,7 @@ our @EXPORT_OK = (
SQLITE_IOERR_FSTAT
SQLITE_IOERR_FSYNC
SQLITE_IOERR_GETTEMPPATH
SQLITE_IOERR_IN_PAGE
SQLITE_IOERR_LOCK
SQLITE_IOERR_MMAP
SQLITE_IOERR_NOMEM
@ -110,10 +160,15 @@ our @EXPORT_OK = (
SQLITE_IOERR_VNODE
SQLITE_IOERR_WRITE
SQLITE_LOCKED_SHAREDCACHE
SQLITE_LOCKED_VTAB
SQLITE_NOTICE_RBU
SQLITE_NOTICE_RECOVER_ROLLBACK
SQLITE_NOTICE_RECOVER_WAL
SQLITE_OK_SYMLINK
SQLITE_READONLY_CANTINIT
SQLITE_READONLY_CANTLOCK
SQLITE_READONLY_DBMOVED
SQLITE_READONLY_DIRECTORY
SQLITE_READONLY_RECOVERY
SQLITE_READONLY_ROLLBACK
SQLITE_WARNING_AUTOINDEX
@ -122,19 +177,26 @@ our @EXPORT_OK = (
# flags_for_file_open_operations
qw/
SQLITE_OPEN_CREATE
SQLITE_OPEN_EXRESCODE
SQLITE_OPEN_FULLMUTEX
SQLITE_OPEN_MEMORY
SQLITE_OPEN_NOFOLLOW
SQLITE_OPEN_NOMUTEX
SQLITE_OPEN_PRIVATECACHE
SQLITE_OPEN_READONLY
SQLITE_OPEN_READWRITE
SQLITE_OPEN_SHAREDCACHE
SQLITE_OPEN_SUPER_JOURNAL
SQLITE_OPEN_URI
/,
# function_flags
qw/
SQLITE_DETERMINISTIC
SQLITE_DIRECTONLY
SQLITE_INNOCUOUS
SQLITE_RESULT_SUBTYPE
SQLITE_SUBTYPE
/,
# fundamental_datatypes
@ -143,6 +205,7 @@ our @EXPORT_OK = (
SQLITE_FLOAT
SQLITE_INTEGER
SQLITE_NULL
SQLITE_TEXT
/,
# result_codes
@ -180,6 +243,22 @@ our @EXPORT_OK = (
SQLITE_WARNING
/,
# run_time_limit_categories
qw/
SQLITE_LIMIT_ATTACHED
SQLITE_LIMIT_COLUMN
SQLITE_LIMIT_COMPOUND_SELECT
SQLITE_LIMIT_EXPR_DEPTH
SQLITE_LIMIT_FUNCTION_ARG
SQLITE_LIMIT_LENGTH
SQLITE_LIMIT_LIKE_PATTERN_LENGTH
SQLITE_LIMIT_SQL_LENGTH
SQLITE_LIMIT_TRIGGER_DEPTH
SQLITE_LIMIT_VARIABLE_NUMBER
SQLITE_LIMIT_VDBE_OP
SQLITE_LIMIT_WORKER_THREADS
/,
);
our %EXPORT_TAGS = (
@ -195,17 +274,22 @@ our %EXPORT_TAGS = (
SQLITE_BUSY
SQLITE_BUSY_RECOVERY
SQLITE_BUSY_SNAPSHOT
SQLITE_BUSY_TIMEOUT
SQLITE_CANTOPEN
SQLITE_CANTOPEN_CONVPATH
SQLITE_CANTOPEN_DIRTYWAL
SQLITE_CANTOPEN_FULLPATH
SQLITE_CANTOPEN_ISDIR
SQLITE_CANTOPEN_NOTEMPDIR
SQLITE_CANTOPEN_SYMLINK
SQLITE_CONSTRAINT
SQLITE_CONSTRAINT_CHECK
SQLITE_CONSTRAINT_COMMITHOOK
SQLITE_CONSTRAINT_DATATYPE
SQLITE_CONSTRAINT_FOREIGNKEY
SQLITE_CONSTRAINT_FUNCTION
SQLITE_CONSTRAINT_NOTNULL
SQLITE_CONSTRAINT_PINNED
SQLITE_CONSTRAINT_PRIMARYKEY
SQLITE_CONSTRAINT_ROWID
SQLITE_CONSTRAINT_TRIGGER
@ -213,6 +297,8 @@ our %EXPORT_TAGS = (
SQLITE_CONSTRAINT_VTAB
SQLITE_COPY
SQLITE_CORRUPT
SQLITE_CORRUPT_INDEX
SQLITE_CORRUPT_SEQUENCE
SQLITE_CORRUPT_VTAB
SQLITE_CREATE_INDEX
SQLITE_CREATE_TABLE
@ -223,10 +309,37 @@ our %EXPORT_TAGS = (
SQLITE_CREATE_TRIGGER
SQLITE_CREATE_VIEW
SQLITE_CREATE_VTABLE
SQLITE_DBCONFIG_DEFENSIVE
SQLITE_DBCONFIG_DQS_DDL
SQLITE_DBCONFIG_DQS_DML
SQLITE_DBCONFIG_ENABLE_FKEY
SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
SQLITE_DBCONFIG_ENABLE_QPSG
SQLITE_DBCONFIG_ENABLE_TRIGGER
SQLITE_DBCONFIG_ENABLE_VIEW
SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
SQLITE_DBCONFIG_LOOKASIDE
SQLITE_DBCONFIG_MAINDBNAME
SQLITE_DBCONFIG_MAX
SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
SQLITE_DBCONFIG_RESET_DATABASE
SQLITE_DBCONFIG_REVERSE_SCANORDER
SQLITE_DBCONFIG_STMT_SCANSTATUS
SQLITE_DBCONFIG_TRIGGER_EQP
SQLITE_DBCONFIG_TRUSTED_SCHEMA
SQLITE_DBCONFIG_WRITABLE_SCHEMA
DBD_SQLITE_STRING_MODE_BYTES
DBD_SQLITE_STRING_MODE_PV
DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK
DBD_SQLITE_STRING_MODE_UNICODE_NAIVE
DBD_SQLITE_STRING_MODE_UNICODE_STRICT
SQLITE_DELETE
SQLITE_DENY
SQLITE_DETACH
SQLITE_DETERMINISTIC
SQLITE_DIRECTONLY
SQLITE_DONE
SQLITE_DROP_INDEX
SQLITE_DROP_TABLE
@ -239,11 +352,15 @@ our %EXPORT_TAGS = (
SQLITE_DROP_VTABLE
SQLITE_EMPTY
SQLITE_ERROR
SQLITE_ERROR_MISSING_COLLSEQ
SQLITE_ERROR_RETRY
SQLITE_ERROR_SNAPSHOT
SQLITE_FLOAT
SQLITE_FORMAT
SQLITE_FULL
SQLITE_FUNCTION
SQLITE_IGNORE
SQLITE_INNOCUOUS
SQLITE_INSERT
SQLITE_INTEGER
SQLITE_INTERNAL
@ -257,6 +374,8 @@ our %EXPORT_TAGS = (
SQLITE_IOERR_CLOSE
SQLITE_IOERR_COMMIT_ATOMIC
SQLITE_IOERR_CONVPATH
SQLITE_IOERR_CORRUPTFS
SQLITE_IOERR_DATA
SQLITE_IOERR_DELETE
SQLITE_IOERR_DELETE_NOENT
SQLITE_IOERR_DIR_CLOSE
@ -264,6 +383,7 @@ our %EXPORT_TAGS = (
SQLITE_IOERR_FSTAT
SQLITE_IOERR_FSYNC
SQLITE_IOERR_GETTEMPPATH
SQLITE_IOERR_IN_PAGE
SQLITE_IOERR_LOCK
SQLITE_IOERR_MMAP
SQLITE_IOERR_NOMEM
@ -280,8 +400,21 @@ our %EXPORT_TAGS = (
SQLITE_IOERR_UNLOCK
SQLITE_IOERR_VNODE
SQLITE_IOERR_WRITE
SQLITE_LIMIT_ATTACHED
SQLITE_LIMIT_COLUMN
SQLITE_LIMIT_COMPOUND_SELECT
SQLITE_LIMIT_EXPR_DEPTH
SQLITE_LIMIT_FUNCTION_ARG
SQLITE_LIMIT_LENGTH
SQLITE_LIMIT_LIKE_PATTERN_LENGTH
SQLITE_LIMIT_SQL_LENGTH
SQLITE_LIMIT_TRIGGER_DEPTH
SQLITE_LIMIT_VARIABLE_NUMBER
SQLITE_LIMIT_VDBE_OP
SQLITE_LIMIT_WORKER_THREADS
SQLITE_LOCKED
SQLITE_LOCKED_SHAREDCACHE
SQLITE_LOCKED_VTAB
SQLITE_MISMATCH
SQLITE_MISUSE
SQLITE_NOLFS
@ -289,18 +422,23 @@ our %EXPORT_TAGS = (
SQLITE_NOTADB
SQLITE_NOTFOUND
SQLITE_NOTICE
SQLITE_NOTICE_RBU
SQLITE_NOTICE_RECOVER_ROLLBACK
SQLITE_NOTICE_RECOVER_WAL
SQLITE_NULL
SQLITE_OK
SQLITE_OK_SYMLINK
SQLITE_OPEN_CREATE
SQLITE_OPEN_EXRESCODE
SQLITE_OPEN_FULLMUTEX
SQLITE_OPEN_MEMORY
SQLITE_OPEN_NOFOLLOW
SQLITE_OPEN_NOMUTEX
SQLITE_OPEN_PRIVATECACHE
SQLITE_OPEN_READONLY
SQLITE_OPEN_READWRITE
SQLITE_OPEN_SHAREDCACHE
SQLITE_OPEN_SUPER_JOURNAL
SQLITE_OPEN_URI
SQLITE_PERM
SQLITE_PRAGMA
@ -308,24 +446,38 @@ our %EXPORT_TAGS = (
SQLITE_RANGE
SQLITE_READ
SQLITE_READONLY
SQLITE_READONLY_CANTINIT
SQLITE_READONLY_CANTLOCK
SQLITE_READONLY_DBMOVED
SQLITE_READONLY_DIRECTORY
SQLITE_READONLY_RECOVERY
SQLITE_READONLY_ROLLBACK
SQLITE_RECURSIVE
SQLITE_REINDEX
SQLITE_RESULT_SUBTYPE
SQLITE_ROW
SQLITE_SAVEPOINT
SQLITE_SCHEMA
SQLITE_SELECT
SQLITE_SUBTYPE
SQLITE_TEXT
SQLITE_TOOBIG
SQLITE_TRANSACTION
SQLITE_TXN_NONE
SQLITE_TXN_READ
SQLITE_TXN_WRITE
SQLITE_UPDATE
SQLITE_VERSION_NUMBER
SQLITE_WARNING
SQLITE_WARNING_AUTOINDEX
/],
allowed_return_values_from_sqlite3_txn_state => [qw/
SQLITE_TXN_NONE
SQLITE_TXN_READ
SQLITE_TXN_WRITE
/],
authorizer_action_codes => [qw/
SQLITE_ALTER_TABLE
SQLITE_ANALYZE
@ -372,26 +524,68 @@ our %EXPORT_TAGS = (
SQLITE_VERSION_NUMBER
/],
database_connection_configuration_options => [qw/
SQLITE_DBCONFIG_DEFENSIVE
SQLITE_DBCONFIG_DQS_DDL
SQLITE_DBCONFIG_DQS_DML
SQLITE_DBCONFIG_ENABLE_FKEY
SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
SQLITE_DBCONFIG_ENABLE_QPSG
SQLITE_DBCONFIG_ENABLE_TRIGGER
SQLITE_DBCONFIG_ENABLE_VIEW
SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
SQLITE_DBCONFIG_LOOKASIDE
SQLITE_DBCONFIG_MAINDBNAME
SQLITE_DBCONFIG_MAX
SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
SQLITE_DBCONFIG_RESET_DATABASE
SQLITE_DBCONFIG_REVERSE_SCANORDER
SQLITE_DBCONFIG_STMT_SCANSTATUS
SQLITE_DBCONFIG_TRIGGER_EQP
SQLITE_DBCONFIG_TRUSTED_SCHEMA
SQLITE_DBCONFIG_WRITABLE_SCHEMA
/],
dbd_sqlite_string_mode => [qw/
DBD_SQLITE_STRING_MODE_BYTES
DBD_SQLITE_STRING_MODE_PV
DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK
DBD_SQLITE_STRING_MODE_UNICODE_NAIVE
DBD_SQLITE_STRING_MODE_UNICODE_STRICT
/],
extended_result_codes => [qw/
SQLITE_ABORT_ROLLBACK
SQLITE_AUTH_USER
SQLITE_BUSY_RECOVERY
SQLITE_BUSY_SNAPSHOT
SQLITE_BUSY_TIMEOUT
SQLITE_CANTOPEN_CONVPATH
SQLITE_CANTOPEN_DIRTYWAL
SQLITE_CANTOPEN_FULLPATH
SQLITE_CANTOPEN_ISDIR
SQLITE_CANTOPEN_NOTEMPDIR
SQLITE_CANTOPEN_SYMLINK
SQLITE_CONSTRAINT_CHECK
SQLITE_CONSTRAINT_COMMITHOOK
SQLITE_CONSTRAINT_DATATYPE
SQLITE_CONSTRAINT_FOREIGNKEY
SQLITE_CONSTRAINT_FUNCTION
SQLITE_CONSTRAINT_NOTNULL
SQLITE_CONSTRAINT_PINNED
SQLITE_CONSTRAINT_PRIMARYKEY
SQLITE_CONSTRAINT_ROWID
SQLITE_CONSTRAINT_TRIGGER
SQLITE_CONSTRAINT_UNIQUE
SQLITE_CONSTRAINT_VTAB
SQLITE_CORRUPT_INDEX
SQLITE_CORRUPT_SEQUENCE
SQLITE_CORRUPT_VTAB
SQLITE_ERROR_MISSING_COLLSEQ
SQLITE_ERROR_RETRY
SQLITE_ERROR_SNAPSHOT
SQLITE_IOERR_ACCESS
SQLITE_IOERR_AUTH
SQLITE_IOERR_BEGIN_ATOMIC
@ -400,6 +594,8 @@ our %EXPORT_TAGS = (
SQLITE_IOERR_CLOSE
SQLITE_IOERR_COMMIT_ATOMIC
SQLITE_IOERR_CONVPATH
SQLITE_IOERR_CORRUPTFS
SQLITE_IOERR_DATA
SQLITE_IOERR_DELETE
SQLITE_IOERR_DELETE_NOENT
SQLITE_IOERR_DIR_CLOSE
@ -407,6 +603,7 @@ our %EXPORT_TAGS = (
SQLITE_IOERR_FSTAT
SQLITE_IOERR_FSYNC
SQLITE_IOERR_GETTEMPPATH
SQLITE_IOERR_IN_PAGE
SQLITE_IOERR_LOCK
SQLITE_IOERR_MMAP
SQLITE_IOERR_NOMEM
@ -424,10 +621,15 @@ our %EXPORT_TAGS = (
SQLITE_IOERR_VNODE
SQLITE_IOERR_WRITE
SQLITE_LOCKED_SHAREDCACHE
SQLITE_LOCKED_VTAB
SQLITE_NOTICE_RBU
SQLITE_NOTICE_RECOVER_ROLLBACK
SQLITE_NOTICE_RECOVER_WAL
SQLITE_OK_SYMLINK
SQLITE_READONLY_CANTINIT
SQLITE_READONLY_CANTLOCK
SQLITE_READONLY_DBMOVED
SQLITE_READONLY_DIRECTORY
SQLITE_READONLY_RECOVERY
SQLITE_READONLY_ROLLBACK
SQLITE_WARNING_AUTOINDEX
@ -435,18 +637,25 @@ our %EXPORT_TAGS = (
flags_for_file_open_operations => [qw/
SQLITE_OPEN_CREATE
SQLITE_OPEN_EXRESCODE
SQLITE_OPEN_FULLMUTEX
SQLITE_OPEN_MEMORY
SQLITE_OPEN_NOFOLLOW
SQLITE_OPEN_NOMUTEX
SQLITE_OPEN_PRIVATECACHE
SQLITE_OPEN_READONLY
SQLITE_OPEN_READWRITE
SQLITE_OPEN_SHAREDCACHE
SQLITE_OPEN_SUPER_JOURNAL
SQLITE_OPEN_URI
/],
function_flags => [qw/
SQLITE_DETERMINISTIC
SQLITE_DIRECTONLY
SQLITE_INNOCUOUS
SQLITE_RESULT_SUBTYPE
SQLITE_SUBTYPE
/],
fundamental_datatypes => [qw/
@ -454,6 +663,7 @@ our %EXPORT_TAGS = (
SQLITE_FLOAT
SQLITE_INTEGER
SQLITE_NULL
SQLITE_TEXT
/],
result_codes => [qw/
@ -490,6 +700,21 @@ our %EXPORT_TAGS = (
SQLITE_WARNING
/],
run_time_limit_categories => [qw/
SQLITE_LIMIT_ATTACHED
SQLITE_LIMIT_COLUMN
SQLITE_LIMIT_COMPOUND_SELECT
SQLITE_LIMIT_EXPR_DEPTH
SQLITE_LIMIT_FUNCTION_ARG
SQLITE_LIMIT_LENGTH
SQLITE_LIMIT_LIKE_PATTERN_LENGTH
SQLITE_LIMIT_SQL_LENGTH
SQLITE_LIMIT_TRIGGER_DEPTH
SQLITE_LIMIT_VARIABLE_NUMBER
SQLITE_LIMIT_VDBE_OP
SQLITE_LIMIT_WORKER_THREADS
/],
);
$EXPORT_TAGS{version} = $EXPORT_TAGS{compile_time_library_version_numbers};
$EXPORT_TAGS{file_open} = $EXPORT_TAGS{flags_for_file_open_operations};
@ -511,12 +736,24 @@ DBD::SQLite::Constants - common SQLite constants
=head1 DESCRIPTION
You can import necessary SQLite constants from this module. Available tags are C<all>, C<authorizer_action_codes>, C<authorizer_return_codes>, C<version> (C<compile_time_library_version_numbers>), C<extended_result_codes>, C<file_open> (C<flags_for_file_open_operations>), C<function_flags>, C<datatypes> (C<fundamental_datatypes>), C<result_codes>. See L<http://sqlite.org/c3ref/constlist.html> for the complete list of constants.
You can import necessary SQLite constants from this module. Available tags are C<all>, C<allowed_return_values_from_sqlite3_txn_state>, C<authorizer_action_codes>, C<authorizer_return_codes>, C<version> (C<compile_time_library_version_numbers>), C<database_connection_configuration_options>, C<dbd_sqlite_string_mode>, C<extended_result_codes>, C<file_open> (C<flags_for_file_open_operations>), C<function_flags>, C<datatypes> (C<fundamental_datatypes>), C<result_codes>, C<run_time_limit_categories>. See L<http://sqlite.org/c3ref/constlist.html> for the complete list of constants.
This module does not export anything by default.
=head1 CONSTANTS
=head2 allowed_return_values_from_sqlite3_txn_state
=over 4
=item SQLITE_TXN_NONE
=item SQLITE_TXN_READ
=item SQLITE_TXN_WRITE
=back
=head2 authorizer_action_codes
=over 4
@ -609,6 +846,70 @@ This module does not export anything by default.
=back
=head2 database_connection_configuration_options
=over 4
=item SQLITE_DBCONFIG_LOOKASIDE
=item SQLITE_DBCONFIG_ENABLE_FKEY
=item SQLITE_DBCONFIG_ENABLE_TRIGGER
=item SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER
=item SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION
=item SQLITE_DBCONFIG_MAINDBNAME
=item SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
=item SQLITE_DBCONFIG_ENABLE_QPSG
=item SQLITE_DBCONFIG_TRIGGER_EQP
=item SQLITE_DBCONFIG_MAX
=item SQLITE_DBCONFIG_RESET_DATABASE
=item SQLITE_DBCONFIG_DEFENSIVE
=item SQLITE_DBCONFIG_WRITABLE_SCHEMA
=item SQLITE_DBCONFIG_LEGACY_ALTER_TABLE
=item SQLITE_DBCONFIG_DQS_DML
=item SQLITE_DBCONFIG_DQS_DDL
=item SQLITE_DBCONFIG_ENABLE_VIEW
=item SQLITE_DBCONFIG_LEGACY_FILE_FORMAT
=item SQLITE_DBCONFIG_TRUSTED_SCHEMA
=item SQLITE_DBCONFIG_STMT_SCANSTATUS
=item SQLITE_DBCONFIG_REVERSE_SCANORDER
=back
=head2 dbd_sqlite_string_mode
=over 4
=item DBD_SQLITE_STRING_MODE_PV
=item DBD_SQLITE_STRING_MODE_BYTES
=item DBD_SQLITE_STRING_MODE_UNICODE_NAIVE
=item DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK
=item DBD_SQLITE_STRING_MODE_UNICODE_STRICT
=back
=head2 extended_result_codes
=over 4
@ -729,6 +1030,42 @@ This module does not export anything by default.
=item SQLITE_IOERR_ROLLBACK_ATOMIC
=item SQLITE_ERROR_MISSING_COLLSEQ
=item SQLITE_ERROR_RETRY
=item SQLITE_READONLY_CANTINIT
=item SQLITE_READONLY_DIRECTORY
=item SQLITE_LOCKED_VTAB
=item SQLITE_CORRUPT_SEQUENCE
=item SQLITE_ERROR_SNAPSHOT
=item SQLITE_CANTOPEN_DIRTYWAL
=item SQLITE_CANTOPEN_SYMLINK
=item SQLITE_CONSTRAINT_PINNED
=item SQLITE_OK_SYMLINK
=item SQLITE_IOERR_DATA
=item SQLITE_BUSY_TIMEOUT
=item SQLITE_CORRUPT_INDEX
=item SQLITE_IOERR_CORRUPTFS
=item SQLITE_CONSTRAINT_DATATYPE
=item SQLITE_NOTICE_RBU
=item SQLITE_IOERR_IN_PAGE
=back
=head2 file_open (flags_for_file_open_operations)
@ -753,6 +1090,12 @@ This module does not export anything by default.
=item SQLITE_OPEN_MEMORY
=item SQLITE_OPEN_NOFOLLOW
=item SQLITE_OPEN_SUPER_JOURNAL
=item SQLITE_OPEN_EXRESCODE
=back
=head2 function_flags
@ -761,6 +1104,14 @@ This module does not export anything by default.
=item SQLITE_DETERMINISTIC
=item SQLITE_DIRECTONLY
=item SQLITE_SUBTYPE
=item SQLITE_INNOCUOUS
=item SQLITE_RESULT_SUBTYPE
=back
=head2 datatypes (fundamental_datatypes)
@ -775,6 +1126,8 @@ This module does not export anything by default.
=item SQLITE_NULL
=item SQLITE_TEXT
=back
=head2 result_codes
@ -845,3 +1198,33 @@ This module does not export anything by default.
=back
=head2 run_time_limit_categories
=over 4
=item SQLITE_LIMIT_LENGTH
=item SQLITE_LIMIT_SQL_LENGTH
=item SQLITE_LIMIT_COLUMN
=item SQLITE_LIMIT_EXPR_DEPTH
=item SQLITE_LIMIT_COMPOUND_SELECT
=item SQLITE_LIMIT_VDBE_OP
=item SQLITE_LIMIT_FUNCTION_ARG
=item SQLITE_LIMIT_ATTACHED
=item SQLITE_LIMIT_LIKE_PATTERN_LENGTH
=item SQLITE_LIMIT_VARIABLE_NUMBER
=item SQLITE_LIMIT_TRIGGER_DEPTH
=item SQLITE_LIMIT_WORKER_THREADS
=back

288
lib/DBD/SQLite/GetInfo.pm Normal file
View file

@ -0,0 +1,288 @@
package DBD::SQLite::GetInfo;
use 5.006;
use strict;
use warnings;
use DBD::SQLite;
# SQL_DRIVER_VER should be formatted as dd.dd.dddd
my $dbdversion = $DBD::SQLite::VERSION;
$dbdversion .= '_00' if $dbdversion =~ /^\d+\.\d+$/;
my $sql_driver_ver = sprintf("%02d.%02d.%04d", split(/[\._]/, $dbdversion));
# Full list of keys and their return types: DBI::Const::GetInfo::ODBC
# Most of the key definitions can be gleaned from:
#
# https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlgetinfo-function
our %info = (
20 => 'N', # SQL_ACCESSIBLE_PROCEDURES - No stored procedures to access
19 => 'Y', # SQL_ACCESSIBLE_TABLES - SELECT access to all tables in table_info
0 => 0, # SQL_ACTIVE_CONNECTIONS - No maximum connection limit
116 => 0, # SQL_ACTIVE_ENVIRONMENTS - No "active environment" limit
1 => 0, # SQL_ACTIVE_STATEMENTS - No concurrent activity limit
169 => 127, # SQL_AGGREGATE_FUNCTIONS - Supports all SQL-92 aggregrate functions
117 => 0, # SQL_ALTER_DOMAIN - No ALTER DOMAIN support
86 => 1, # SQL_ALTER_TABLE - Only supports ADD COLUMN and table rename (not listed in enum) in ALTER TABLE statements
10021 => 0, # SQL_ASYNC_MODE - No asynchronous support (in vanilla SQLite)
120 => 0, # SQL_BATCH_ROW_COUNT - No special row counting access
121 => 0, # SQL_BATCH_SUPPORT - No batches
82 => 0, # SQL_BOOKMARK_PERSISTENCE - No bookmark support
114 => 1, # SQL_CATALOG_LOCATION - Database comes first in identifiers
10003 => 'Y', # SQL_CATALOG_NAME - Supports database names
41 => '.', # SQL_CATALOG_NAME_SEPARATOR - Separated by dot
42 => 'database', # SQL_CATALOG_TERM - SQLite calls catalogs databases
92 => 1+4+8, # SQL_CATALOG_USAGE - Supported in calls to DML & table/index definiton (no procedures or permissions)
10004 => 'UTF-8', # SQL_COLLATION_SEQ - SQLite 3 uses UTF-8 by default
87 => 'Y', # SQL_COLUMN_ALIAS - Supports column aliases
22 => 0, # SQL_CONCAT_NULL_BEHAVIOR - 'a'||NULL = NULL
# SQLite has no CONVERT function, only CAST. However, it converts to every "affinity" it supports.
#
# The only SQL_CVT_* types it doesn't support are date/time types, as it has no concept of
# date/time values once inserted. These are only convertable to text-like types. GUIDs are in
# the same boat, having no real means of switching to a numeric format.
#
# text/binary types = 31723265
# numeric types = 28926
# date/time types = 1802240
# total = 33554431
48 => 1, # SQL_CONVERT_FUNCTIONS - CAST only
53 => 31723265+28926, # SQL_CONVERT_BIGINT
54 => 31723265+28926, # SQL_CONVERT_BINARY
55 => 31723265+28926, # SQL_CONVERT_BIT
56 => 33554431, # SQL_CONVERT_CHAR
57 => 31723265+1802240, # SQL_CONVERT_DATE
58 => 31723265+28926, # SQL_CONVERT_DECIMAL
59 => 31723265+28926, # SQL_CONVERT_DOUBLE
60 => 31723265+28926, # SQL_CONVERT_FLOAT
173 => 31723265, # SQL_CONVERT_GUID
61 => 31723265+28926, # SQL_CONVERT_INTEGER
123 => 31723265+1802240, # SQL_CONVERT_INTERVAL_DAY_TIME
124 => 31723265+1802240, # SQL_CONVERT_INTERVAL_YEAR_MONTH
71 => 31723265+28926, # SQL_CONVERT_LONGVARBINARY
62 => 31723265+28926, # SQL_CONVERT_LONGVARCHAR
63 => 31723265+28926, # SQL_CONVERT_NUMERIC
64 => 31723265+28926, # SQL_CONVERT_REAL
65 => 31723265+28926, # SQL_CONVERT_SMALLINT
66 => 31723265+1802240, # SQL_CONVERT_TIME
67 => 31723265+1802240, # SQL_CONVERT_TIMESTAMP
68 => 31723265+28926, # SQL_CONVERT_TINYINT
69 => 33554431, # SQL_CONVERT_VARBINARY
70 => 33554431, # SQL_CONVERT_VARCHAR
122 => 33554431, # SQL_CONVERT_WCHAR
125 => 33554431, # SQL_CONVERT_WLONGVARCHAR
126 => 33554431, # SQL_CONVERT_WVARCHAR
74 => 1, # SQL_CORRELATION_NAME - Table aliases are supported, but must be named differently
127 => 0, # SQL_CREATE_ASSERTION - No CREATE ASSERTION support
128 => 0, # SQL_CREATE_CHARACTER_SET - No CREATE CHARACTER SET support
129 => 0, # SQL_CREATE_COLLATION - No CREATE COLLATION support
130 => 0, # SQL_CREATE_DOMAIN - No CREATE DOMAIN support
131 => 0, # SQL_CREATE_SCHEMA - No CREATE SCHEMA support
132 => 16383-2-8-4096, # SQL_CREATE_TABLE - Most of the functionality of CREATE TABLE support
133 => 0, # SQL_CREATE_TRANSLATION - No CREATE TRANSLATION support
134 => 1, # SQL_CREATE_VIEW - CREATE VIEW, no WITH CHECK OPTION support
23 => 2, # SQL_CURSOR_COMMIT_BEHAVIOR - Cursors are preserved
24 => 2, # SQL_CURSOR_ROLLBACK_BEHAVIOR - Cursors are preserved
10001 => 0, # SQL_CURSOR_SENSITIVITY - Cursors have a concept of snapshots, though this depends on the transaction type
2 => \&sql_data_source_name, # SQL_DATA_SOURCE_NAME - The DSN
25 => \&sql_data_source_read_only, # SQL_DATA_SOURCE_READ_ONLY - Might have a SQLITE_OPEN_READONLY flag
16 => \&sql_database_name, # SQL_DATABASE_NAME - Self-explanatory
119 => 0, # SQL_DATETIME_LITERALS - No support for SQL-92's super weird date/time literal format (ie: {d '2999-12-12'})
17 => 'SQLite', # SQL_DBMS_NAME - You are here
18 => \&sql_dbms_ver, # SQL_DBMS_VER - This driver version
170 => 1+2, # SQL_DDL_INDEX - Supports CREATE/DROP INDEX
26 => 8, # SQL_DEFAULT_TXN_ISOLATION - Default is SERIALIZABLE (See "PRAGMA read_uncommitted")
10002 => 'N', # SQL_DESCRIBE_PARAMETER - No DESCRIBE INPUT support
# XXX: MySQL/Oracle fills in HDBC and HENV, but information on what should actually go there is
# hard to acquire.
# 171 => undef, # SQL_DM_VER - Not a Driver Manager
# 3 => undef, # SQL_DRIVER_HDBC - Not a Driver Manager
# 135 => undef, # SQL_DRIVER_HDESC - Not a Driver Manager
# 4 => undef, # SQL_DRIVER_HENV - Not a Driver Manager
# 76 => undef, # SQL_DRIVER_HLIB - Not a Driver Manager
# 5 => undef, # SQL_DRIVER_HSTMT - Not a Driver Manager
6 => 'libsqlite3odbc.so', # SQL_DRIVER_NAME - SQLite3 ODBC driver (if installed)
77 => '03.00', # SQL_DRIVER_ODBC_VER - Same as sqlite3odbc.c
7 => $sql_driver_ver, # SQL_DRIVER_VER - Self-explanatory
136 => 0, # SQL_DROP_ASSERTION - No DROP ASSERTION support
137 => 0, # SQL_DROP_CHARACTER_SET - No DROP CHARACTER SET support
138 => 0, # SQL_DROP_COLLATION - No DROP COLLATION support
139 => 0, # SQL_DROP_DOMAIN - No DROP DOMAIN support
140 => 0, # SQL_DROP_SCHEMA - No DROP SCHEMA support
141 => 1, # SQL_DROP_TABLE - DROP TABLE support, no RESTRICT/CASCADE
142 => 0, # SQL_DROP_TRANSLATION - No DROP TRANSLATION support
143 => 1, # SQL_DROP_VIEW - DROP VIEW support, no RESTRICT/CASCADE
# NOTE: This is based purely on what sqlite3odbc supports.
#
# Static CA1: NEXT, ABSOLUTE, RELATIVE, BOOKMARK, LOCK_NO_CHANGE, POSITION, UPDATE, DELETE, REFRESH,
# BULK_ADD, BULK_UPDATE_BY_BOOKMARK, BULK_DELETE_BY_BOOKMARK = 466511
#
# Forward-only CA1: NEXT, BOOKMARK
#
# CA2: READ_ONLY_CONCURRENCY, LOCK_CONCURRENCY
144 => 0, # SQL_DYNAMIC_CURSOR_ATTRIBUTES1 - No dynamic cursor support
145 => 0, # SQL_DYNAMIC_CURSOR_ATTRIBUTES2 - No dynamic cursor support
146 => 1+8, # SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1
147 => 1+2, # SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2
150 => 0, # SQL_KEYSET_CURSOR_ATTRIBUTES1 - No keyset cursor support
151 => 0, # SQL_KEYSET_CURSOR_ATTRIBUTES2 - No keyset cursor support
167 => 466511, # SQL_STATIC_CURSOR_ATTRIBUTES1
168 => 1+2, # SQL_STATIC_CURSOR_ATTRIBUTES2
27 => 'Y', # SQL_EXPRESSIONS_IN_ORDERBY - ORDER BY allows expressions
8 => 63, # SQL_FETCH_DIRECTION - Cursors support next, first, last, prior, absolute, relative
84 => 2, # SQL_FILE_USAGE - Single-tier driver, treats files as databases
81 => 1+2+8, # SQL_GETDATA_EXTENSIONS - Same as sqlite3odbc.c
88 => 3, # SQL_GROUP_BY - SELECT columns are independent of GROUP BY columns
28 => 4, # SQL_IDENTIFIER_CASE - Not case-sensitive, stored in mixed case
29 => '"', # SQL_IDENTIFIER_QUOTE_CHAR - Uses " for identifiers, though supports [] and ` as well
148 => 0, # SQL_INDEX_KEYWORDS - No support for ASC/DESC/ALL for CREATE INDEX
149 => 0, # SQL_INFO_SCHEMA_VIEWS - No support for INFORMATION_SCHEMA
172 => 1+2, # SQL_INSERT_STATEMENT - INSERT...VALUES & INSERT...SELECT
73 => 'N', # SQL_INTEGRITY - No support for "Integrity Enhancement Facility"
89 => \&sql_keywords, # SQL_KEYWORDS - List of non-ODBC keywords
113 => 'Y', # SQL_LIKE_ESCAPE_CLAUSE - Supports LIKE...ESCAPE
78 => 1, # SQL_LOCK_TYPES - Only NO_CHANGE
10022 => 0, # SQL_MAX_ASYNC_CONCURRENT_STATEMENTS - No async mode
112 => 1_000_000, # SQL_MAX_BINARY_LITERAL_LEN - SQLITE_MAX_SQL_LENGTH
34 => 1_000_000, # SQL_MAX_CATALOG_NAME_LEN - SQLITE_MAX_SQL_LENGTH
108 => 1_000_000, # SQL_MAX_CHAR_LITERAL_LEN - SQLITE_MAX_SQL_LENGTH
97 => 2000, # SQL_MAX_COLUMNS_IN_GROUP_BY - SQLITE_MAX_COLUMN
98 => 2000, # SQL_MAX_COLUMNS_IN_INDEX - SQLITE_MAX_COLUMN
99 => 2000, # SQL_MAX_COLUMNS_IN_ORDER_BY - SQLITE_MAX_COLUMN
100 => 2000, # SQL_MAX_COLUMNS_IN_SELECT - SQLITE_MAX_COLUMN
101 => 2000, # SQL_MAX_COLUMNS_IN_TABLE - SQLITE_MAX_COLUMN
30 => 1_000_000, # SQL_MAX_COLUMN_NAME_LEN - SQLITE_MAX_SQL_LENGTH
1 => 1021, # SQL_MAX_CONCURRENT_ACTIVITIES - Typical filehandle limits
31 => 1_000_000, # SQL_MAX_CURSOR_NAME_LEN - SQLITE_MAX_SQL_LENGTH
0 => 1021, # SQL_MAX_DRIVER_CONNECTIONS - Typical filehandle limits
10005 => 1_000_000, # SQL_MAX_IDENTIFIER_LEN - SQLITE_MAX_SQL_LENGTH
102 => 2147483646*65536, # SQL_MAX_INDEX_SIZE - Tied to DB size, which is theortically 140TB
32 => 1_000_000, # SQL_MAX_OWNER_NAME_LEN - SQLITE_MAX_SQL_LENGTH
33 => 1_000_000, # SQL_MAX_PROCEDURE_NAME_LEN - SQLITE_MAX_SQL_LENGTH
34 => 1_000_000, # SQL_MAX_QUALIFIER_NAME_LEN - SQLITE_MAX_SQL_LENGTH
104 => 1_000_000, # SQL_MAX_ROW_SIZE - SQLITE_MAX_SQL_LENGTH (since INSERT has to be used)
103 => 'Y', # SQL_MAX_ROW_SIZE_INCLUDES_LONG
32 => 1_000_000, # SQL_MAX_SCHEMA_NAME_LEN - SQLITE_MAX_SQL_LENGTH
105 => 1_000_000, # SQL_MAX_STATEMENT_LEN - SQLITE_MAX_SQL_LENGTH
106 => 64, # SQL_MAX_TABLES_IN_SELECT - 64 tables, because of the bitmap in the query optimizer
35 => 1_000_000, # SQL_MAX_TABLE_NAME_LEN - SQLITE_MAX_SQL_LENGTH
107 => 0, # SQL_MAX_USER_NAME_LEN - No user support
37 => 'Y', # SQL_MULTIPLE_ACTIVE_TXN - Supports mulitple txns, though not nested
36 => 'N', # SQL_MULT_RESULT_SETS - No batches
111 => 'N', # SQL_NEED_LONG_DATA_LEN - Doesn't care about LONG
75 => 1, # SQL_NON_NULLABLE_COLUMNS - Supports NOT NULL
85 => 1, # SQL_NULL_COLLATION - NULLs first on ASC (low end)
49 => 4194304+1, # SQL_NUMERIC_FUNCTIONS - Just ABS & ROUND (has RANDOM, but not RAND)
9 => 1, # SQL_ODBC_API_CONFORMANCE - Same as sqlite3odbc.c
152 => 1, # SQL_ODBC_INTERFACE_CONFORMANCE - Same as sqlite3odbc.c
12 => 0, # SQL_ODBC_SAG_CLI_CONFORMANCE - Same as sqlite3odbc.c
15 => 0, # SQL_ODBC_SQL_CONFORMANCE - Same as sqlite3odbc.c
10 => '03.00', # SQL_ODBC_VER - Same as sqlite3odbc.c
115 => 1+8+16+32+64, # SQL_OJ_CAPABILITIES - Supports all OUTER JOINs except RIGHT & FULL
90 => 'N', # SQL_ORDER_BY_COLUMNS_IN_SELECT - ORDER BY columns don't have to be in the SELECT list
38 => 'Y', # SQL_OUTER_JOINS - Supports OUTER JOINs
153 => 2, # SQL_PARAM_ARRAY_ROW_COUNTS - Only has row counts for executed statements
154 => 3, # SQL_PARAM_ARRAY_SELECTS - No support for arrays of parameters
80 => 0, # SQL_POSITIONED_STATEMENTS - No support for positioned statements (WHERE CURRENT OF or SELECT FOR UPDATE)
79 => 31, # SQL_POS_OPERATIONS - Supports all SQLSetPos operations
21 => 'N', # SQL_PROCEDURES - No procedures
40 => '', # SQL_PROCEDURE_TERM - No procedures
93 => 4, # SQL_QUOTED_IDENTIFIER_CASE - Even quoted identifiers are case-insensitive
11 => 'N', # SQL_ROW_UPDATES - No fancy cursor update support
39 => '', # SQL_SCHEMA_TERM - No schemas
91 => 0, # SQL_SCHEMA_USAGE - No schemas
43 => 2, # SQL_SCROLL_CONCURRENCY - Updates/deletes on cursors lock the database
44 => 1+16, # SQL_SCROLL_OPTIONS - Only supports static & forward-only cursors
14 => '\\', # SQL_SEARCH_PATTERN_ESCAPE - Default escape character for LIKE is \
13 => \&sql_server_name, # SQL_SERVER_NAME - Just $dbh->{Name}
94 => '', # SQL_SPECIAL_CHARACTERS - Other drivers tend to stick to the ASCII/Latin-1 range, and SQLite uses all of
# the lower 7-bit punctuation for other things
155 => 7, # SQL_SQL92_DATETIME_FUNCTIONS - Supports CURRENT_(DATE|TIME|TIMESTAMP)
156 => 1+2+4+8, # SQL_SQL92_FOREIGN_KEY_DELETE_RULE - Support all ON DELETE options
157 => 1+2+4+8, # SQL_SQL92_FOREIGN_KEY_UPDATE_RULE - Support all ON UPDATE options
158 => 0, # SQL_SQL92_GRANT - No users; no support for GRANT
159 => 0, # SQL_SQL92_NUMERIC_VALUE_FUNCTIONS - No support for any of the listed functions
160 => 1+2+4+512+1024+2048+4096+8192, # SQL_SQL92_PREDICATES - Supports the important comparison operators
161 => 2+16+64+128, # SQL_SQL92_RELATIONAL_JOIN_OPERATORS - Supports the important ones except RIGHT/FULL OUTER JOINs
162 => 0, # SQL_SQL92_REVOKE - No users; no support for REVOKE
163 => 1+2+8, # SQL_SQL92_ROW_VALUE_CONSTRUCTOR - Supports most row value constructors
164 => 2+4, # SQL_SQL92_STRING_FUNCTIONS - Just UPPER & LOWER (has SUBSTR, but not SUBSTRING and SQL-92's weird TRIM syntax)
165 => 1+2+4+8, # SQL_SQL92_VALUE_EXPRESSIONS - Supports all SQL-92 value expressions
118 => 1, # SQL_SQL_CONFORMANCE - SQL-92 Entry level
83 => 0, # SQL_STATIC_SENSITIVITY - Cursors would lock the DB, so only old data is visible
50 => 8+16+256+1024+16384+131072, # SQL_STRING_FUNCTIONS - LTRIM, LENGTH, REPLACE, RTRIM, CHAR, SOUNDEX
95 => 1+2+4+8+16, # SQL_SUBQUERIES - Supports all of the subquery types
51 => 4, # SQL_SYSTEM_FUNCTIONS - Only IFNULL
45 => 'table', # SQL_TABLE_TERM - Tables are called tables
109 => 0, # SQL_TIMEDATE_ADD_INTERVALS - No support for INTERVAL
110 => 0, # SQL_TIMEDATE_DIFF_INTERVALS - No support for INTERVAL
52 => 0x20000+0x40000+0x80000, # SQL_TIMEDATE_FUNCTIONS - Only supports CURRENT_(DATE|TIME|TIMESTAMP)
46 => 2, # SQL_TXN_CAPABLE - Full transaction support for both DML & DDL
72 => 1+8, # SQL_TXN_ISOLATION_OPTION - Supports read uncommitted and serializable
96 => 1+2, # SQL_UNION - Supports UNION and UNION ALL
47 => '', # SQL_USER_NAME - No users
166 => 1, # SQL_STANDARD_CLI_CONFORMANCE - X/Open CLI Version 1.0
10000 => 1992, # SQL_XOPEN_CLI_YEAR - Year for V1.0
);
sub sql_dbms_ver {
my $dbh = shift;
return $dbh->FETCH('sqlite_version');
}
sub sql_data_source_name {
my $dbh = shift;
return "dbi:SQLite:".$dbh->{Name};
}
sub sql_data_source_read_only {
my $dbh = shift;
my $flags = $dbh->FETCH('sqlite_open_flags') || 0;
return $dbh->{ReadOnly} || ($flags & DBD::SQLite::OPEN_READONLY()) ? 'Y' : 'N';
}
sub sql_database_name {
my $dbh = shift;
my $databases = $dbh->selectall_hashref('PRAGMA database_list', 'seq');
return $databases->{0}{name};
}
sub sql_keywords {
# SQLite keywords minus ODBC keywords
return join ',', (qw<
ABORT AFTER ANALYZE ATTACH AUTOINCREMENT BEFORE CONFLICT DATABASE DETACH EACH EXCLUSIVE
EXPLAIN FAIL GLOB IF IGNORE INDEXED INSTEAD ISNULL LIMIT NOTNULL OFFSET
PLAN PRAGMA QUERY RAISE RECURSIVE REGEXP REINDEX RELEASE RENAME REPLACE ROW
SAVEPOINT TEMP TRIGGER VACUUM VIRTUAL WITHOUT
>);
}
sub sql_server_name {
my $dbh = shift;
return $dbh->{Name};
}
1;
__END__

View file

@ -5,7 +5,7 @@ use strict;
use warnings;
use Scalar::Util qw/weaken/;
our $VERSION = '1.56';
our $VERSION = '1.76';
our @ISA;

View file

@ -88,7 +88,7 @@ sub BEST_INDEX {
# in FILTER() for deciding which rows match the constraints.
my @conditions;
my $ix = 0;
foreach my $constraint (grep {$_->{usable}} @$constraints) {
foreach my $constraint (grep {$_->{usable} and exists $SQLOP2PERLOP{ $_->{op} } } @$constraints) {
my $col = $constraint->{col};
my ($member, $optype);
@ -389,7 +389,7 @@ time. Here is a way to do it with a virtual table :
my @files = ... ; # list of files to inspect
# apply the L<stat> function to each file
our $file_stats = [ map {($_, stat $_)} @files];
our $file_stats = [ map { [ $_, stat $_ ] } @files];
# create a temporary virtual table
$dbh->do(<<"");

102051
sqlite3.c

File diff suppressed because it is too large Load diff

3776
sqlite3.h

File diff suppressed because it is too large Load diff

View file

@ -295,6 +295,77 @@ struct sqlite3_api_routines {
int (*vtab_nochange)(sqlite3_context*);
int (*value_nochange)(sqlite3_value*);
const char *(*vtab_collation)(sqlite3_index_info*,int);
/* Version 3.24.0 and later */
int (*keyword_count)(void);
int (*keyword_name)(int,const char**,int*);
int (*keyword_check)(const char*,int);
sqlite3_str *(*str_new)(sqlite3*);
char *(*str_finish)(sqlite3_str*);
void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
void (*str_append)(sqlite3_str*, const char *zIn, int N);
void (*str_appendall)(sqlite3_str*, const char *zIn);
void (*str_appendchar)(sqlite3_str*, int N, char C);
void (*str_reset)(sqlite3_str*);
int (*str_errcode)(sqlite3_str*);
int (*str_length)(sqlite3_str*);
char *(*str_value)(sqlite3_str*);
/* Version 3.25.0 and later */
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
void (*xValue)(sqlite3_context*),
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
void(*xDestroy)(void*));
/* Version 3.26.0 and later */
const char *(*normalized_sql)(sqlite3_stmt*);
/* Version 3.28.0 and later */
int (*stmt_isexplain)(sqlite3_stmt*);
int (*value_frombind)(sqlite3_value*);
/* Version 3.30.0 and later */
int (*drop_modules)(sqlite3*,const char**);
/* Version 3.31.0 and later */
sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
const char *(*uri_key)(const char*,int);
const char *(*filename_database)(const char*);
const char *(*filename_journal)(const char*);
const char *(*filename_wal)(const char*);
/* Version 3.32.0 and later */
const char *(*create_filename)(const char*,const char*,const char*,
int,const char**);
void (*free_filename)(const char*);
sqlite3_file *(*database_file_object)(const char*);
/* Version 3.34.0 and later */
int (*txn_state)(sqlite3*,const char*);
/* Version 3.36.1 and later */
sqlite3_int64 (*changes64)(sqlite3*);
sqlite3_int64 (*total_changes64)(sqlite3*);
/* Version 3.37.0 and later */
int (*autovacuum_pages)(sqlite3*,
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
void*, void(*)(void*));
/* Version 3.38.0 and later */
int (*error_offset)(sqlite3*);
int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
int (*vtab_distinct)(sqlite3_index_info*);
int (*vtab_in)(sqlite3_index_info*,int,int);
int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
/* Version 3.39.0 and later */
int (*deserialize)(sqlite3*,const char*,unsigned char*,
sqlite3_int64,sqlite3_int64,unsigned);
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
unsigned int);
const char *(*db_name)(sqlite3*,int);
/* Version 3.40.0 and later */
int (*value_encoding)(sqlite3_value*);
/* Version 3.41.0 and later */
int (*is_interrupted)(sqlite3*);
/* Version 3.43.0 and later */
int (*stmt_explain)(sqlite3_stmt*,int);
/* Version 3.44.0 and later */
void *(*get_clientdata)(sqlite3*,const char*);
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
};
/*
@ -563,8 +634,71 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_value_pointer sqlite3_api->value_pointer
/* Version 3.22.0 and later */
#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
#define sqlite3_value_nochange sqltie3_api->value_nochange
#define sqlite3_vtab_collation sqltie3_api->vtab_collation
#define sqlite3_value_nochange sqlite3_api->value_nochange
#define sqlite3_vtab_collation sqlite3_api->vtab_collation
/* Version 3.24.0 and later */
#define sqlite3_keyword_count sqlite3_api->keyword_count
#define sqlite3_keyword_name sqlite3_api->keyword_name
#define sqlite3_keyword_check sqlite3_api->keyword_check
#define sqlite3_str_new sqlite3_api->str_new
#define sqlite3_str_finish sqlite3_api->str_finish
#define sqlite3_str_appendf sqlite3_api->str_appendf
#define sqlite3_str_vappendf sqlite3_api->str_vappendf
#define sqlite3_str_append sqlite3_api->str_append
#define sqlite3_str_appendall sqlite3_api->str_appendall
#define sqlite3_str_appendchar sqlite3_api->str_appendchar
#define sqlite3_str_reset sqlite3_api->str_reset
#define sqlite3_str_errcode sqlite3_api->str_errcode
#define sqlite3_str_length sqlite3_api->str_length
#define sqlite3_str_value sqlite3_api->str_value
/* Version 3.25.0 and later */
#define sqlite3_create_window_function sqlite3_api->create_window_function
/* Version 3.26.0 and later */
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
/* Version 3.28.0 and later */
#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain
#define sqlite3_value_frombind sqlite3_api->value_frombind
/* Version 3.30.0 and later */
#define sqlite3_drop_modules sqlite3_api->drop_modules
/* Version 3.31.0 and later */
#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
#define sqlite3_uri_key sqlite3_api->uri_key
#define sqlite3_filename_database sqlite3_api->filename_database
#define sqlite3_filename_journal sqlite3_api->filename_journal
#define sqlite3_filename_wal sqlite3_api->filename_wal
/* Version 3.32.0 and later */
#define sqlite3_create_filename sqlite3_api->create_filename
#define sqlite3_free_filename sqlite3_api->free_filename
#define sqlite3_database_file_object sqlite3_api->database_file_object
/* Version 3.34.0 and later */
#define sqlite3_txn_state sqlite3_api->txn_state
/* Version 3.36.1 and later */
#define sqlite3_changes64 sqlite3_api->changes64
#define sqlite3_total_changes64 sqlite3_api->total_changes64
/* Version 3.37.0 and later */
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
/* Version 3.38.0 and later */
#define sqlite3_error_offset sqlite3_api->error_offset
#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct
#define sqlite3_vtab_in sqlite3_api->vtab_in
#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
/* Version 3.39.0 and later */
#ifndef SQLITE_OMIT_DESERIALIZE
#define sqlite3_deserialize sqlite3_api->deserialize
#define sqlite3_serialize sqlite3_api->serialize
#endif
#define sqlite3_db_name sqlite3_api->db_name
/* Version 3.40.0 and later */
#define sqlite3_value_encoding sqlite3_api->value_encoding
/* Version 3.41.0 and later */
#define sqlite3_is_interrupted sqlite3_api->is_interrupted
/* Version 3.43.0 and later */
#define sqlite3_stmt_explain sqlite3_api->stmt_explain
/* Version 3.44.0 and later */
#define sqlite3_get_clientdata sqlite3_api->get_clientdata
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)

View file

@ -1,15 +1,9 @@
#!/usr/bin/perl
# Test that everything compiles, so the rest of the test suite can
# load modules without having to check if it worked.
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use Test::More tests => 3;
use warnings;
use Test::More;
use lib "t/lib";
@ -23,3 +17,5 @@ if (my @compile_options = DBD::SQLite::compile_options()) {
diag("Compile Options:");
diag(join "", map { " $_\n" } @compile_options);
}
done_testing;

View file

@ -1,19 +1,15 @@
#!/usr/bin/perl
# Tests basic login and pragma setting
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS/;
use Test::More;
use Test::NoWarnings;
use if -d ".git", "Test::FailWarnings";
plan tests => 20 * @CALL_FUNCS + 1;
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
my $unicode_opt = DBD_SQLITE_STRING_MODE_UNICODE_STRICT;
my $show_diag = 0;
foreach my $call_func (@CALL_FUNCS) {
@ -38,9 +34,9 @@ foreach my $call_func (@CALL_FUNCS) {
skip( 'Unicode is not supported before 5.8.5', 2 );
}
my $file = 'foo'.$$;
my $dbh = DBI->connect( "dbi:SQLite:dbname=$file;sqlite_unicode=1", '', '' );
my $dbh = DBI->connect( "dbi:SQLite:dbname=$file;sqlite_string_mode=$unicode_opt", '', '' );
isa_ok( $dbh, 'DBI::db' );
is( $dbh->{sqlite_unicode}, 1, 'Unicode is on' );
is( $dbh->{sqlite_string_mode}, $unicode_opt, 'Unicode is on' );
$dbh->disconnect;
unlink $file;
}
@ -65,3 +61,5 @@ foreach my $call_func (@CALL_FUNCS) {
isa_ok( $dbh, 'DBI::db' );
}
}
done_testing;

View file

@ -1,17 +1,11 @@
#!/usr/bin/perl
# Tests simple table creation
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 7;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok();
$dbh->do(<<'END_SQL');
@ -35,3 +29,4 @@ my $names = $sth->{NAME};
is( scalar(@$names), 4, 'Got 4 columns' );
is_deeply( $names, [ 'f1', 'f1', 'f2', 'f3' ], 'Table prepending is disabled by default' );
done_testing;

View file

@ -1,15 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 14;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok();
@ -40,3 +34,5 @@ SCOPE: {
}
is( $dbh->do("delete from f where f1='test'"), 3 );
done_testing;

View file

@ -1,15 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 22;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok( RaiseError => 1 );
$dbh->do("CREATE TABLE f (f1, f2, f3)");
@ -61,3 +55,5 @@ while ($row = $sth->fetch) {
ok($num_rows == 1);
$sth->finish;
$dbh->do("delete from f where f1='test'");
done_testing;

View file

@ -1,15 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 6;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok(
AutoCommit => 0,
@ -54,3 +48,5 @@ $dbh->rollback;
);
ok !$dbh->{sqlite_use_immediate_transaction}, "sqlite_use_immediate_transaction is false if you set explicitly";
}
done_testing;

View file

@ -1,15 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 8;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok( RaiseError => 1, PrintError => 0 );
eval {
@ -30,3 +24,13 @@ eval {
ok($@, 'Statement 2 generated an error');
is( $DBI::err, 19, '$DBI::err ok' );
like( $DBI::errstr, qr/column a is not unique|UNIQUE constraint failed/, '$DBI::errstr ok' );
if ($DBD::SQLite::sqlite_version_number && $DBD::SQLite::sqlite_version_number >= 3038000) {
my $sql = 'insert testerror values (1, 5)';
eval { $dbh->do($sql) };
my $offset = $dbh->sqlite_error_offset;
ok $offset != -1, "error offset: $offset";
note substr($sql, 0, $offset) . '<*error*>' . substr($sql, $offset);
}
done_testing;

View file

@ -1,19 +1,11 @@
#!/usr/bin/perl
# Test that two processes can write at once, assuming we commit timely.
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok dbfile @CALL_FUNCS/;
use Test::More;
use Test::NoWarnings;
plan tests => 11 * @CALL_FUNCS + 1;
use if -d ".git", "Test::FailWarnings";
foreach my $call_func (@CALL_FUNCS) {
@ -125,3 +117,5 @@ foreach my $call_func (@CALL_FUNCS) {
unlink $dbfile;
}
}
done_testing;

View file

@ -1,26 +1,20 @@
#!/usr/bin/perl
use 5.00503;
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS/;
use Test::More;
use Test::NoWarnings;
use if -d ".git", "Test::FailWarnings";
use DBD::SQLite;
use DBD::SQLite::Constants;
use Digest::MD5 qw/md5/;
use DBI qw/:sql_types/;
my @function_flags = (undef, 0);
if ($DBD::SQLite::sqlite_version_number >= 3008003) {
push @function_flags, DBD::SQLite::Constants::SQLITE_DETERMINISTIC;
}
plan tests => 29 * @CALL_FUNCS * @function_flags + 1;
sub now {
return time();
}
@ -61,6 +55,14 @@ sub noop {
return $_[0];
}
sub md5_text {
return md5($_[0]);
}
sub md5_blob {
return [md5($_[0]), SQL_BLOB];
}
foreach my $call_func (@CALL_FUNCS) { for my $flags (@function_flags) {
my $dbh = connect_ok( PrintError => 0 );
@ -134,5 +136,25 @@ foreach my $call_func (@CALL_FUNCS) { for my $flags (@function_flags) {
$result = $dbh->selectrow_arrayref( "SELECT typeof(noop(2147483648))" );
is_deeply( $result, [ 'integer' ], "SELECT typeof(noop(2147483648))" );
ok($dbh->$call_func( "md5_text", 1, \&md5_text, defined $flags ? $flags : (), "create_function" ));
$result = $dbh->selectrow_arrayref( "SELECT md5_text('my_blob')" );
is_deeply( $result, [ md5('my_blob') ], "SELECT md5_text('my_blob')" );
$result = $dbh->selectrow_arrayref( "SELECT typeof(md5_text('my_blob'))" );
is_deeply( $result, [ 'text' ], "SELECT typeof(md5_text('my_blob'))" );
ok($dbh->$call_func( "md5_blob", 1, \&md5_blob, defined $flags ? $flags : (), "create_function" ));
$result = $dbh->selectrow_arrayref( "SELECT md5_blob('my_blob')" );
is_deeply( $result, [ md5('my_blob') ], "SELECT md5_blob('my_blob')" );
$result = $dbh->selectrow_arrayref( "SELECT typeof(md5_blob('my_blob'))" );
is_deeply( $result, [ 'blob' ], "SELECT typeof(md5_blob('my_blob'))" );
ok($dbh->$call_func( "md5_blob", 1, undef, defined $flags ? $flags : (), "create_function" ));
$result = $dbh->selectrow_arrayref( "SELECT md5_blob('my_blob')" );
is_deeply( $result, undef, "SELECT md5_blob('my_blob')" );
$dbh->disconnect;
}}
done_testing;

View file

@ -1,15 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS/;
use Test::More;
use Test::NoWarnings;
use if -d ".git", "Test::FailWarnings";
use DBD::SQLite;
use DBD::SQLite::Constants;
@ -18,8 +12,6 @@ if ($DBD::SQLite::sqlite_version_number >= 3008003) {
push @function_flags, DBD::SQLite::Constants::SQLITE_DETERMINISTIC;
}
plan tests => 21 * @CALL_FUNCS * @function_flags + 1;
# Create the aggregate test packages
SCOPE: {
package count_aggr;
@ -94,7 +86,6 @@ foreach my $call_func (@CALL_FUNCS) { for my $flags (@function_flags) {
$result = $dbh->selectall_arrayref( "SELECT newcount() FROM aggr_test GROUP BY field" );
ok( @$result == 3 && $result->[0][0] == 1 && $result->[1][0] == 1 );
# Test aggregate on empty table
$dbh->do( "DROP TABLE aggr_empty_test;" );
$dbh->do( "CREATE TABLE aggr_empty_test ( field )" );
@ -141,3 +132,5 @@ foreach my $call_func (@CALL_FUNCS) { for my $flags (@function_flags) {
$dbh->disconnect;
}}
done_testing;

49
t/11_get_info.t Normal file
View file

@ -0,0 +1,49 @@
use strict;
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
use if -d ".git", "Test::FailWarnings";
use DBI::Const::GetInfoType;
# NOTE: These are tests for just a very basic set of get_info variables.
my %info = (
SQL_CATALOG_LOCATION => 1,
SQL_CATALOG_NAME => 'Y',
SQL_CATALOG_NAME_SEPARATOR => '.',
SQL_CATALOG_TERM => 'database',
# some of these are dynamic, but always the same for connect_ok
SQL_DATA_SOURCE_NAME => qr/^dbi:SQLite:dbname=/,
SQL_DATA_SOURCE_READ_ONLY => 'N',
SQL_DATABASE_NAME => 'main',
SQL_DBMS_NAME => 'SQLite',
SQL_DBMS_VER => qr/^[1-9]+\.\d+\.\d+$/,
SQL_IDENTIFIER_QUOTE_CHAR => '"',
SQL_MAX_IDENTIFIER_LEN => qr/^[1-9]\d+$/,
SQL_MAX_TABLE_NAME_LEN => qr/^[1-9]\d+$/,
SQL_KEYWORDS => qr/^(?:\w+,)+\w+$/,
SQL_SEARCH_PATTERN_ESCAPE => '\\',
SQL_SERVER_NAME => qr/^dbname=/,
SQL_TABLE_TERM => 'table',
);
my $dbh = connect_ok( RaiseError => 1 );
foreach my $option ( sort keys %info ) {
my $value = $dbh->get_info( $GetInfoType{$option} );
my $check = $info{$option};
if (ref $check eq 'Regexp') { like($value, $check, $option); }
else { is ($value, $check, $option); }
}
$dbh->disconnect;
done_testing;

View file

@ -1,25 +1,18 @@
#!/usr/bin/perl
# This is a test for correct handling of the "unicode" database
# handle parameter.
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
BEGIN {
if ( $] >= 5.008005 ) {
plan( tests => 26 );
} else {
plan( skip_all => 'Unicode is not supported before 5.8.5' );
}
}
use Test::NoWarnings;
use if -d ".git", "Test::FailWarnings";
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
my $unicode_opt = DBD_SQLITE_STRING_MODE_UNICODE_STRICT;
BEGIN { requires_unicode_support() }
#
# Include std stuff
@ -62,7 +55,7 @@ ok(
my ($textback, $bytesback);
SCOPE: {
my $dbh = connect_ok( dbfile => 'foo', RaiseError => 1 );
is( $dbh->{sqlite_unicode}, 0, 'Unicode is off' );
is( $dbh->{sqlite_string_mode}, DBD::SQLite::Constants::DBD_SQLITE_STRING_MODE_PV, 'default string mode is pv' );
ok(
$dbh->do("CREATE TABLE table1 (a TEXT, b BLOB)"),
'CREATE TABLE',
@ -84,8 +77,8 @@ SCOPE: {
# Start over but now activate Unicode support.
SCOPE: {
my $dbh = connect_ok( dbfile => 'foo', sqlite_unicode => 1 );
is( $dbh->{sqlite_unicode}, 1, 'Unicode is on' );
my $dbh = connect_ok( dbfile => 'foo', sqlite_string_mode => $unicode_opt );
is( $dbh->{sqlite_string_mode}, $unicode_opt, 'Unicode is on' );
($textback, $bytesback) = database_roundtrip($dbh, $utfstring, $bytestring);
@ -137,3 +130,5 @@ sub database_roundtrip {
croak "Bad row length ".@row unless (@row == 2);
@row;
}
done_testing;

View file

@ -1,28 +1,17 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
no if $] >= 5.022, "warnings", "locale";
use lib "t/lib";
use SQLiteTest qw/connect_ok dies @CALL_FUNCS/;
use SQLiteTest;
use Test::More;
BEGIN {
my $COLLATION_TESTS = 10;
my $WRITE_ONCE_TESTS = 4;
if ( $] >= 5.008005 ) {
plan( tests => $COLLATION_TESTS * @CALL_FUNCS +
$WRITE_ONCE_TESTS + 1);
} else {
plan( skip_all => 'Unicode is not supported before 5.8.5' );
}
}
use Test::NoWarnings;
use if -d ".git", "Test::FailWarnings";
use Encode qw/decode/;
use DBD::SQLite;
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
my $unicode_opt = DBD_SQLITE_STRING_MODE_UNICODE_STRICT;
BEGIN { requires_unicode_support(); }
BEGIN {
# Sadly perl for windows (and probably sqlite, too) may hang
@ -53,17 +42,13 @@ sub by_num_desc ($$) {
$_[1] <=> $_[0];
}
# collation 'no_accents' will be automatically loaded on demand
$DBD::SQLite::COLLATION{no_accents} = \&no_accents;
$" = ", "; # to embed arrays into message strings
my $sql = "SELECT txt from collate_test ORDER BY txt";
# test interaction with the global COLLATION hash ("WriteOnce")
dies (sub {$DBD::SQLite::COLLATION{perl} = sub {}},
@ -85,16 +70,14 @@ delete $tied->{foo};
$DBD::SQLite::COLLATION{foo} = \&by_num_desc; # override, no longer dies
is($DBD::SQLite::COLLATION{foo}, \&by_num_desc, "overridden collation");
# now really test the collation functions
foreach my $call_func (@CALL_FUNCS) {
for my $use_unicode (0, 1) {
for my $unicode_opt (DBD_SQLITE_STRING_MODE_BYTES, DBD_SQLITE_STRING_MODE_UNICODE_STRICT) {
# connect
my $dbh = connect_ok( RaiseError => 1, sqlite_unicode => $use_unicode );
my $dbh = connect_ok( RaiseError => 1, sqlite_string_mode => $unicode_opt );
# populate test data
my @words = qw{
@ -104,7 +87,7 @@ foreach my $call_func (@CALL_FUNCS) {
HAT hâôer
féôu fêôe fèöe ferme
};
if ($use_unicode) {
if ($unicode_opt != DBD_SQLITE_STRING_MODE_BYTES) {
utf8::upgrade($_) foreach @words;
}
@ -132,7 +115,6 @@ foreach my $call_func (@CALL_FUNCS) {
is_deeply(\@sorted, $db_sorted,
"collate no_accents (@sorted // @$db_sorted)");
# manual addition of a collation for this dbh
$dbh->$call_func(by_length => \&by_length, "create_collation");
@sorted = sort by_length @words;
@ -142,6 +124,4 @@ foreach my $call_func (@CALL_FUNCS) {
}
}
done_testing;

View file

@ -1,17 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS/;
use Test::More;
use Test::NoWarnings;
plan tests => 5 * @CALL_FUNCS + 1;
use if -d ".git", "Test::FailWarnings";
my $N_OPCODES = 50; # how many opcodes before calling the progress handler
@ -44,7 +36,6 @@ foreach my $call_func (@CALL_FUNCS) {
# now the progress handler should have been called a number of times
ok($n_callback);
# unregister the progress handler, set counter back to zero, do more work
ok($dbh->$call_func( $N_OPCODES, undef, "progress_handler" ));
$n_callback = 0;
@ -55,3 +46,5 @@ foreach my $call_func (@CALL_FUNCS) {
$dbh->disconnect;
}
done_testing;

View file

@ -1,15 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 37;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
# Create a database
my $dbh = connect_ok( dbfile => 'foo', RaiseError => 1, PrintError => 1, PrintWarn => 1 );
@ -116,7 +110,6 @@ SCOPE: {
ok( $sth->finish, '->finish' );
}
# Delete the test row from the table
ok( $dbh->do('DELETE FROM ONE WHERE id = 2 AND name IS NULL'), 'DELETE' );
@ -137,3 +130,5 @@ SCOPE: {
my $sth = $dbh->prepare("UPDATE one SET id = 3 WHERE name = 'Gary Shea'");
isa_ok( $sth, 'DBI::st' );
}
done_testing;

View file

@ -1,15 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 12;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
my $dbh = DBI->connect('dbi:SQLite:dbname=:memory:',undef,undef,{RaiseError => 1});
@ -81,3 +75,5 @@ SKIP: {
# 11. Correct info retrieved
is_deeply( \@info, $expected, 'We got the right info from multiple databases' );
}
done_testing;

View file

@ -1,18 +1,12 @@
#!/usr/bin/perl
# This is a skeleton test. For writing new tests, take this file
# and modify/extend it.
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 4;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
# Create a database
my $dbh = connect_ok();
@ -27,3 +21,5 @@ END_SQL
# Drop the table
ok( $dbh->do('DROP TABLE one'), 'DROP TABLE' );
done_testing;

View file

@ -1,17 +1,11 @@
#!/usr/bin/perl
# This is a simple insert/fetch test.
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 10;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
# Create a database
my $dbh = connect_ok( RaiseError => 1 );
@ -47,3 +41,5 @@ SCOPE: {
my $row2 = $sth->fetchrow_arrayref;
is( $row2, undef, 'fetch empty statement handler' );
}
done_testing;

View file

@ -1,15 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 39;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
use DBI ':sql_types';
# Create a database
@ -87,3 +81,5 @@ SCOPE: {
is( $id, 6, 'id = 6' );
is( $name, 'Larry', 'name = Larry' );
}
done_testing;

View file

@ -1,18 +1,12 @@
#!/usr/bin/perl
# This is a test for correct handling of BLOBS; namely $dbh->quote
# is expected to work correctly.
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 17;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
use DBI ':sql_types';
sub ShowBlob($) {
@ -72,6 +66,26 @@ SCOPE: {
ok( $sth->bind_param(1, 3), '->bind_param' );
ok( $sth->bind_param(2, undef, SQL_BLOB), '->bind_param' );
ok( $sth->execute, '->execute' );
ok my $quoted_blob = $dbh->quote($blob, SQL_BLOB);
ok( $dbh->do("INSERT INTO one VALUES( 4, $quoted_blob )"), 'insert quoted blob' );
ok my $quoted_empty = $dbh->quote('', SQL_BLOB);
ok( $dbh->do("INSERT INTO one VALUES( 5, $quoted_empty )"), 'insert quoted empty string' );
ok my $quoted_undef = $dbh->quote(undef, SQL_BLOB);
ok( $dbh->do("INSERT INTO one VALUES( 6, $quoted_undef )"), 'insert quoted undef' );
ok my $quoted_bit = $dbh->quote($blob, SQL_BIT);
ok( $dbh->do("INSERT INTO one VALUES( 7, $quoted_bit )"), 'insert quoted bit' );
ok my $quoted_binary = $dbh->quote($blob, SQL_BINARY);
ok( $dbh->do("INSERT INTO one VALUES( 8, $quoted_binary )"), 'insert quoted binary' );
ok my $quoted_varbinary = $dbh->quote($blob, SQL_VARBINARY);
ok( $dbh->do("INSERT INTO one VALUES( 9, $quoted_varbinary )"), 'insert quoted varbinary' );
ok my $quoted_longvarbinary = $dbh->quote($blob, SQL_LONGVARBINARY);
ok( $dbh->do("INSERT INTO one VALUES( 10, $quoted_longvarbinary )"), 'insert quoted longvarbinary' );
}
# Now, try SELECT'ing the row out.
@ -84,6 +98,15 @@ SCOPE: {
[ 1, $blob ],
[ 2, '' ],
[ 3, undef ],
[ 4, $blob ],
[ 5, '' ],
[ 6, undef ],
[ 7, $blob ],
[ 8, $blob ],
[ 9, $blob ],
[ 10, $blob ],
], 'Got the blob back ok' );
ok( $sth->finish, '->finish' );
}
done_testing;

View file

@ -1,15 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 27;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok(
RaiseError => 1,
@ -81,3 +75,4 @@ sub dumpblob {
if ($ENV{SHOW_BLOBS}) { close(OUT) }
}
done_testing;

View file

@ -1,17 +1,11 @@
#!/usr/bin/perl
# This is a test for statement attributes being present appropriately.
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 12;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
# Create a database
my $dbh = connect_ok();
@ -46,3 +40,5 @@ SCOPE: {
is( $sth->{NUM_OF_FIELDS}, 0, 'No fields in statement' );
ok( $sth->finish, '->finish ok' );
}
done_testing;

View file

@ -1,16 +1,11 @@
#!/usr/bin/perl
# This is a test for correctly handling NULL values.
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 9;
use Test::More;
use if -d ".git", "Test::FailWarnings";
# Create a database
my $dbh = connect_ok();
@ -40,3 +35,5 @@ SCOPE: {
is( $row->[1], 'NULL-valued id', 'Second column is defined' );
ok( $sth->finish, '->finish' );
}
done_testing;

View file

@ -1,17 +1,11 @@
#!/usr/bin/perl
# This tests, whether the number of rows can be retrieved.
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 18;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
sub rows {
my $sth = shift;
@ -78,3 +72,5 @@ SCOPE: {
rows( $sth, 2 );
ok( $sth->finish, '->finish' );
}
done_testing;

View file

@ -1,17 +1,11 @@
#!/usr/bin/perl
# Check whether 'ChopBlanks' works.
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 14;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
# Create a database
my $dbh = connect_ok( RaiseError => 1 );
@ -67,3 +61,5 @@ SCOPE: {
], 'ChopBlanks = 1' );
ok( $sth->finish, '->finish' );
}
done_testing;

View file

@ -1,23 +1,14 @@
#!/usr/bin/perl
# This is testing the transaction support.
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 28;
# use Test::NoWarnings;
use Test::More;
# use if -d ".git", "Test::FailWarnings";
my $warning_count = 0;
#####################################################################
# Support functions
@ -38,10 +29,6 @@ sub rows {
);
}
#####################################################################
# Main Tests
@ -120,3 +107,5 @@ SCOPE: {
$SIG{__WARN__} = 'DEFAULT';
is( $warning_count, 2, 'Got one warning' );
}
done_testing;

View file

@ -1,14 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use Test::More tests => 21;
use warnings;
use Test::More;
use lib "t/lib";
use SQLiteTest;
use if -d ".git", "Test::FailWarnings";
# 1-4. Connect & create tables
my $dbh = connect_ok(dbfile => 'foo');
@ -45,16 +40,17 @@ $dbh->do("INSERT INTO meta4 VALUES ('xyz', 'b')");
$sth = $dbh->prepare('SELECT * FROM meta4');
$sth->execute;
$sth->fetch;
$dbh->{sqlite_prefer_numeric_type} = 1;
my $types = $sth->{TYPE};
my $names = $sth->{NAME};
# diag "Types: @$types\nNames: @$names";
is scalar @$types, scalar @$names, '$sth->{TYPE} array is same length as $sth->{NAME} array';
# FIXME: This is wrong! $sth->{TYPE} should return an array of integers see: rt #46873
TODO: {
local $TODO = '$sth->{TYPE} should return an array of integers.';
# $sth->{TYPE} should return an array of integers see: rt #46873
isnt $types->[0], 'VARCHAR(2)', '$sth->{TYPE}[0] doesn\'t return a string';
isnt $types->[1], 'CHAR(1)', '$sth->{TYPE}[1] doesn\'t return a string';
like $types->[0], qr/^-?\d+$/, '$sth->{TYPE}[0] returns an integer';
like $types->[1], qr/^-?\d+$/, '$sth->{TYPE}[1] returns an integer';
}
done_testing;

View file

@ -1,17 +1,12 @@
#!/usr/bin/perl
# This test works, but as far as I can tell this doesn't actually test
# the thing that the test was originally meant to test.
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use Test::More tests => 9;
use warnings;
use Test::More;
use lib "t/lib";
use SQLiteTest;
use if -d ".git", "Test::FailWarnings";
my $create1 = 'CREATE TABLE table1 (id INTEGER NOT NULL, name CHAR (64) NOT NULL)';
my $create2 = 'CREATE TABLE table2 (id INTEGER NOT NULL, name CHAR (64) NOT NULL)';
@ -59,3 +54,5 @@ SCOPE: {
ok( $dbh->do($create2), $create2 ) or diag("Error: '$DBI::errstr'");
ok( $dbh->disconnect, '->disconnect ok' );
}
done_testing;

View file

@ -1,17 +1,11 @@
#!/usr/bin/perl
# I've disabled warnings, so theoretically warnings shouldn't be printed
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 6;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
SCOPE: {
my $dbh = connect_ok( RaiseError => 1, PrintWarn => 0, Warn => 0 );
@ -23,3 +17,5 @@ SCOPE: {
'INSERT ok',
);
}
done_testing;

View file

@ -1,17 +1,12 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
my @to_be_tested;
BEGIN { @to_be_tested = (1.23E4); }
use Test::More tests => 2 + @to_be_tested;
use Test::More;
use lib "t/lib";
use SQLiteTest;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok();
@ -25,3 +20,5 @@ SCOPE: {
ok( (@$av && $av->[0] == $to_be_tested[$id]), "accepts $to_be_tested[$id]: ".$av->[0]);
}
}
done_testing;

View file

@ -1,14 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use Test::More tests => 4;
use warnings;
use Test::More;
use lib "t/lib";
use SQLiteTest;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok( PrintError => 0, RaiseError => 0 );
@ -33,3 +28,20 @@ like(
qr/attempt to execute on inactive database handle/,
'Got the expected warning',
);
@warning = ();
SCOPE: {
local $SIG{__WARN__} = sub { push @warning, @_; return };
my $ret = eval { $sth->{NUM_OF_PARAMS}; };
# we need PrintError => 1, or warn $@ if $@;
ok !$ret;
}
is( scalar(@warning), 1, 'Got 1 warning' );
like(
$warning[0],
qr/attempt to fetch on inactive database handle/,
'Got the expected warning',
);
done_testing;

View file

@ -1,28 +1,21 @@
#!/usr/bin/perl
# Tests path containing non-latine-1 characters
# currently fails on Windows
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
BEGIN {
if ( $] >= 5.008005 ) {
plan( tests => 2 + 12 * (($^O eq 'cygwin') ? 2 : 4) );
} else {
plan( skip_all => 'Unicode is not supported before 5.8.5' );
}
}
#use Test::NoWarnings;
use if -d ".git", "Test::FailWarnings";
use File::Temp ();
use File::Spec::Functions ':ALL';
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
my $unicode_opt = DBD_SQLITE_STRING_MODE_UNICODE_STRICT;
BEGIN { requires_unicode_support() }
my $dir = File::Temp::tempdir( CLEANUP => 1 );
foreach my $subdir ( 'longascii', 'adatbázis', 'name with spaces', '¿¿¿ ¿¿¿¿¿¿') {
if ($^O eq 'cygwin') {
@ -66,7 +59,7 @@ foreach my $subdir ( 'longascii', 'adatb
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile", undef, undef, {
RaiseError => 1,
PrintError => 0,
sqlite_unicode => 1,
sqlite_string_mode => $unicode_opt,
} );
isa_ok( $dbh, 'DBI::db' );
};
@ -78,7 +71,7 @@ foreach my $subdir ( 'longascii', 'adatb
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile", undef, undef, {
RaiseError => 1,
PrintError => 0,
sqlite_unicode => 1,
sqlite_string_mode => $unicode_opt,
} );
isa_ok( $dbh, 'DBI::db' );
};
@ -104,7 +97,6 @@ foreach my $subdir ( 'longascii', 'adatb
unlink(_path($dbfilex)) if -e _path($dbfilex);
}
# connect to an empty filename - sqlite will create a tempfile
eval {
my $dbh = DBI->connect("dbi:SQLite:dbname=", undef, undef, {
@ -116,9 +108,6 @@ eval {
is( $@, '', "Could connect to temp database (empty filename)" );
diag( $@ ) if $@;
sub _path { # copied from DBD::SQLite::connect
my $path = shift;
@ -137,3 +126,5 @@ sub _path { # copied from DBD::SQLite::connect
}
return $path;
}
done_testing;

View file

@ -1,5 +1,3 @@
#!/usr/bin/perl
use strict;
use warnings;
@ -9,11 +7,9 @@ use SQLiteTest qw/connect_ok dbfile @CALL_FUNCS requires_sqlite/;
BEGIN { requires_sqlite('3.6.11') }
use Test::NoWarnings;
use if -d ".git", "Test::FailWarnings";
use DBI;
plan tests => 6 * @CALL_FUNCS + 1;
foreach my $call_func (@CALL_FUNCS) {
# Connect to the test db and add some stuff:
my $foo = connect_ok( dbfile => 'foo', RaiseError => 1 );
@ -69,3 +65,47 @@ foreach my $call_func (@CALL_FUNCS) {
unlink $dbfile;
}
foreach my $call_func (@CALL_FUNCS) {
# Connect to the test db and add some stuff:
my $foo = connect_ok( dbfile => ':memory:', RaiseError => 1 );
$foo->do(
'CREATE TABLE online_backup_test( id INTEGER PRIMARY KEY, foo INTEGER )'
);
$foo->do("INSERT INTO online_backup_test (foo) VALUES ($$)");
my $dbh = DBI->connect(
'dbi:SQLite:dbname=:memory:',
undef, undef,
{ RaiseError => 1 }
);
ok($dbh->$call_func($foo, 'backup_from_dbh'));
{
my ($count) = $dbh->selectrow_array(
"SELECT count(foo) FROM online_backup_test WHERE foo=$$"
);
is($count, 1, "Found our process ID in backed-up table");
}
# Add more data then attempt to copy it back to file:
$dbh->do(
'CREATE TABLE online_backup_test2 ( id INTEGER PRIMARY KEY, foo INTEGER )'
);
$dbh->do("INSERT INTO online_backup_test2 (foo) VALUES ($$)");
# backup to dbh (foo):
ok($dbh->$call_func($foo, 'backup_to_dbh'));
$dbh->disconnect;
my ($count) = $foo->selectrow_array(
"SELECT count(foo) FROM online_backup_test2 WHERE foo=$$"
);
is($count, 1, "Found our process ID in table back on disk");
$foo->disconnect;
}
done_testing;

View file

@ -1,15 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More tests => 22;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
my @catalog_info = (
[undef, undef, undef, undef, undef],
@ -146,3 +140,4 @@ is_deeply $info, [$table2_info, @systable_info, $table4_info, $table3_info, $tab
#warn 'Table Types', substr Dumper($dbh->table_info('', '', '', '%')->fetchall_arrayref), 5;
#warn 'table_info', substr Dumper($info), 5;
done_testing;

View file

@ -1,20 +1,12 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS/;
use SQLiteTest;
use Test::More;
use Test::NoWarnings qw/had_no_warnings clear_warnings/;
use if -d ".git", "Test::FailWarnings";
use DBD::SQLite;
plan tests => 24 * @CALL_FUNCS + 1;
# hooks : just count the commits / rollbacks / updates
my ($n_commits, $n_rollbacks, $n_updates, @update_args);
sub commit_hook { $n_commits += 1; return 0; }
@ -71,15 +63,12 @@ foreach my $call_func (@CALL_FUNCS) {
is($n_commits, 0, "commit hook unregistered");
is($n_updates, 0, "update hook unregistered");
# check here explicitly for warnings, before we clear them
had_no_warnings();
# remember how many rows we had so far
my ($n_rows) = $dbh->selectrow_array($sql_count_rows);
# a commit hook that rejects the transaction
$dbh->$call_func(sub {return 1}, "commit_hook");
eval {do_transaction($dbh)}; # in eval() because of RaiseError
allow_warnings { eval {do_transaction($dbh)} }; # in eval() because of RaiseError
ok ($@, "transaction was rejected: $@" );
# no explicit rollback, because SQLite already did it
@ -96,7 +85,7 @@ foreach my $call_func (@CALL_FUNCS) {
# try transaction again .. rollback hook should not be called
$n_rollbacks = 0;
eval {do_transaction($dbh)};
allow_warnings { eval {do_transaction($dbh)} };
is($n_rollbacks, 0, "rollback hook unregistered");
# check that the rollbacks did really occur
@ -122,26 +111,18 @@ foreach my $call_func (@CALL_FUNCS) {
"args to authorizer (INSERT)");
# try a delete (should be unauthorized)
eval {$dbh->do("DELETE FROM hook_test WHERE foo = 'auth_test'")};
allow_warnings { eval {$dbh->do("DELETE FROM hook_test WHERE foo = 'auth_test'")} };
ok($@, "delete was rejected with message $@");
is_deeply(\@authorizer_args,
[DBD::SQLite::DELETE, 'hook_test', undef, 'temp', undef],
"args to authorizer (DELETE)");
# unregister the authorizer ... now DELETE should be authorized
$dbh->$call_func(undef, "set_authorizer");
eval {$dbh->do("DELETE FROM hook_test WHERE foo = 'auth_test'")};
allow_warnings { eval {$dbh->do("DELETE FROM hook_test WHERE foo = 'auth_test'")} };
ok(!$@, "delete was accepted");
# sqlite3 did warn in tests above, so avoid complains from Test::Warnings
# (would be better to turn off warnings from sqlite3, but I didn't find
# any way to do that)
clear_warnings();
}
sub do_transaction {
my $dbh = shift;
@ -152,3 +133,5 @@ sub do_transaction {
}
$dbh->commit;
}
done_testing;

View file

@ -1,14 +1,10 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
no if $] >= 5.022, "warnings", "locale";
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS/;
use SQLiteTest;
use Test::More;
use if -d ".git", "Test::FailWarnings";
my @words = qw{
berger Bergère bergère Bergere
@ -19,14 +15,7 @@ my @words = qw{
};
my @regexes = qw( ^b\\w+ (?i:^b\\w+) );
BEGIN {
if ($] < 5.008005) {
plan skip_all => 'Unicode is not supported before 5.8.5';
}
}
plan tests => 2 * (3 + 2 * @regexes) * @CALL_FUNCS;
BEGIN { requires_unicode_support() }
BEGIN {
# Sadly perl for windows (and probably sqlite, too) may hang
# if the system locale doesn't support european languages.
@ -39,15 +28,14 @@ BEGIN {
use locale;
use DBD::SQLite;
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
foreach my $call_func (@CALL_FUNCS) {
for my $use_unicode (0, 1) {
for my $string_mode (DBD_SQLITE_STRING_MODE_BYTES, DBD_SQLITE_STRING_MODE_UNICODE_STRICT) {
# connect
my $dbh = connect_ok( RaiseError => 1, sqlite_unicode => $use_unicode );
my $dbh = connect_ok( RaiseError => 1, sqlite_string_mode => $string_mode );
# The following tests are about ordering, so don't reverse!
if ($dbh->selectrow_array('PRAGMA reverse_unordered_selects')) {
@ -56,7 +44,7 @@ foreach my $call_func (@CALL_FUNCS) {
# populate test data
my @vals = @words;
if ($use_unicode) {
if ($string_mode == DBD_SQLITE_STRING_MODE_BYTES) {
utf8::upgrade($_) foreach @vals;
}
@ -92,3 +80,4 @@ foreach my $call_func (@CALL_FUNCS) {
}
}
done_testing;

View file

@ -1,17 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok/;
use Test::More;
use Test::NoWarnings;
plan tests => 8;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok( RaiseError => 1 );
@ -38,3 +30,5 @@ diag $@ if $@;
eval { $dbh->do(undef) };
ok !$@, "undef statement does not spit a warning, and does not die anyway";
diag $@ if $@;
done_testing;

View file

@ -1,20 +1,12 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
BEGIN { requires_sqlite('3.6.19') }
use Test::NoWarnings;
plan tests => 17;
use if -d ".git", "Test::FailWarnings";
# following tests are from http://www.sqlite.org/foreignkeys.html
@ -77,3 +69,5 @@ sub insert_track { _do("INSERT INTO track (trackid, trackname, trackartist) VAL
sub update_track { _do("UPDATE track SET trackartist = ? WHERE trackname = ?", @_); }
sub _do { eval { $dbh->do(shift, undef, @_) }; }
done_testing;

View file

@ -1,17 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok/;
use Test::More;
use Test::NoWarnings;
plan tests => 21;
use if -d ".git", "Test::FailWarnings";
{
# DBD::SQLite prepares/does the first statement only;
@ -132,3 +124,5 @@ plan tests => 21;
ok $got->[0][0] == 1
&& $got->[1][0] == 2, "and got the inserted values";
}
done_testing;

View file

@ -1,17 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok/;
use Test::More;
use Test::NoWarnings;
plan tests => 13;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok( RaiseError => 1 );
ok $dbh->do('create table foo (id integer, value integer)');
@ -58,3 +50,5 @@ SKIP: {
ok $count == 2;
}
done_testing;

View file

@ -1,17 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok/;
use Test::More;
use Test::NoWarnings;
plan tests => (5 * 5) + (3 * 6 + 1) + (5 * 2) + 1;
use if -d ".git", "Test::FailWarnings";
for my $quote ('', qw/' " ` []/) {
my ($begin_quote, $end_quote) = (substr($quote, 0, 1), substr($quote, -1, 1));
@ -119,3 +111,5 @@ for my $quote ('', qw/' " ` []/) {
is $pk_info[0]{PK_NAME} => 'bar', "pk name is correct";
}
}
done_testing;

View file

@ -1,14 +1,15 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok has_sqlite/;
use Time::HiRes qw/time/;
use SQLiteTest;
use Test::More;
use if -d ".git", "Test::FailWarnings";
use DBD::SQLite;
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
# Avoid slowdown with -DDEBUGGING:
${^UTF8CACHE} = 1;
my @texts = ("il était une bergère",
"qui gardait ses moutons",
@ -27,71 +28,52 @@ my @tests = (
["(il OR elle) AND un*" => 0, 2 ],
);
my $ix_une_native = index($texts[0], "une");
my $ix_une_utf8 = do {use bytes; utf8::upgrade(my $bergere_utf8 = $texts[0]); index($bergere_utf8, "une");};
BEGIN {
if ($] < 5.008005) {
plan skip_all => 'Unicode is not supported before 5.8.5';
requires_unicode_support();
if (!has_fts()) {
plan skip_all => 'FTS is disabled for this DBD::SQLite';
}
if (!grep /ENABLE_FTS3/, DBD::SQLite::compile_options()) {
plan skip_all => 'FTS3 is disabled for this DBD::SQLite';
}
if ($DBD::SQLite::sqlite_version_number >= 3011000 and $DBD::SQLite::sqlite_version_number < 3012000 and !grep /ENABLE_FTS3_TOKENIZER/, DBD::SQLite::compile_options()) {
if ($DBD::SQLite::sqlite_version_number >= 3011000 and $DBD::SQLite::sqlite_version_number < 3012000 and !has_compile_option('ENABLE_FTS3_TOKENIZER')) {
plan skip_all => 'FTS3 tokenizer is disabled for this DBD::SQLite';
}
}
# Perl may spit a warning on locale
# use Test::NoWarnings;
my $num = has_sqlite('3.7.4') ? 4 : 2;
plan tests => $num * @tests # each test with unicode y/n and with fts3/fts4
+ 2; # connect_ok with unicode y/n
BEGIN {
# Sadly perl for windows (and probably sqlite, too) may hang
# if the system locale doesn't support european languages.
# en-us should be a safe default. if it doesn't work, use 'C'.
if ( $^O eq 'MSWin32') {
use POSIX 'locale_h';
setlocale(LC_COLLATE, 'en-us');
}
}
use locale;
sub locale_tokenizer { # see also: Search::Tokenizer
sub Unicode_Word_tokenizer { # see also: Search::Tokenizer
return sub {
my $string = shift;
my $regex = qr/\w+/;
my $regex = qr/\p{Word}+/;
my $term_index = 0;
return sub {
$string =~ /$regex/g or return; # either match, or no more token
my ($start, $end) = ($-[0], $+[0]);
my $term = substr($string, $start, my $len = $end-$start);
my $term = $&;
my $end = pos $string; # $+[0] is much slower
my $len = length($term);
my $start = $end - $len;
return ($term, $len, $start, $end, $term_index++);
};
};
}
use DBD::SQLite;
for my $use_unicode (0, 1) {
for my $string_mode (DBD_SQLITE_STRING_MODE_BYTES, DBD_SQLITE_STRING_MODE_UNICODE_STRICT) {
# connect
my $dbh = connect_ok( RaiseError => 1, sqlite_unicode => $use_unicode );
my $dbh = connect_ok( RaiseError => 1, sqlite_string_mode => $string_mode );
for my $fts (qw/fts3 fts4/) {
next if $fts eq 'fts4' && !has_sqlite('3.7.4');
# create fts table
$dbh->do(<<"") or die DBI::errstr;
CREATE VIRTUAL TABLE try_$fts
USING $fts(content, tokenize=perl 'main::locale_tokenizer')
USING $fts(content, tokenize=perl 'main::Unicode_Word_tokenizer')
# populate it
my $insert_sth = $dbh->prepare(<<"") or die DBI::errstr;
@ -107,17 +89,52 @@ for my $use_unicode (0, 1) {
SKIP: {
skip "These tests require SQLite compiled with "
. "ENABLE_FTS3_PARENTHESIS option", scalar @tests
unless DBD::SQLite->can('compile_options') &&
grep /ENABLE_FTS3_PARENTHESIS/, DBD::SQLite::compile_options();
unless has_compile_option('ENABLE_FTS3_PARENTHESIS');
my $sql = "SELECT docid FROM try_$fts WHERE content MATCH ?";
for my $t (@tests) {
my ($query, @expected) = @$t;
@expected = map {$doc_ids[$_]} @expected;
my $results = $dbh->selectcol_arrayref($sql, undef, $query);
is_deeply($results, \@expected, "$query ($fts, unicode=$use_unicode)");
}
}
is_deeply($results, \@expected, "$query ($fts, string_mode=$string_mode)");
}
}
# the 'snippet' function should highlight the words in the MATCH query
my $sql_snip = "SELECT snippet(try_$fts) FROM try_$fts WHERE content MATCH ?";
my $result = $dbh->selectcol_arrayref($sql_snip, undef, 'une');
is_deeply($result, ['il était <b>une</b> bergère'], "snippet ($fts, string_mode=$string_mode)");
# the 'offsets' function should return integer offsets for the words in the MATCH query
my $sql_offsets = "SELECT offsets(try_$fts) FROM try_$fts WHERE content MATCH ?";
$result = $dbh->selectcol_arrayref($sql_offsets, undef, 'une');
my $offset_une = $string_mode == DBD_SQLITE_STRING_MODE_UNICODE_STRICT ? $ix_une_utf8 : $ix_une_native;
my $expected_offsets = "0 0 $offset_une 3";
is_deeply($result, [$expected_offsets], "offsets ($fts, string_mode=$string_mode)");
# test snippet() on a longer sentence
$insert_sth->execute(join " ", @texts);
$result = $dbh->selectcol_arrayref($sql_snip, undef, '"bergère qui gardait"');
like($result->[0],
qr[une <b>bergère</b> <b>qui</b> <b>gardait</b> ses],
"longer snippet ($fts, string_mode=$string_mode)");
# simulated large document
open my $fh, "<", $INC{'DBD/SQLite.pm'} or die $!;
my $source_code = do {local $/; <$fh>};
my $long_doc = $source_code x 5;
my $t0 = time;
$insert_sth->execute($long_doc);
my $t1 = time;
$result = $dbh->selectcol_arrayref($sql_snip, undef, '"package DBD::SQLite"');
my $t2 = time;
note sprintf("long doc (%d chars): insert in %.4f secs, select in %.4f secs",
length($long_doc), $t1-$t0, $t2-$t1);
like($result->[0], qr[^<b>package</b> <b>DBD</b>::<b>SQLite</b>;], 'snippet "package SQLite"');
}
}
done_testing;

View file

@ -1,16 +1,15 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
use DBD::SQLite;
use Data::Dumper;
use if -d ".git", "Test::FailWarnings";
BEGIN {
if (!has_compile_option('ENABLE_RTREE')) {
plan skip_all => 'RTREE is disabled for this DBD::SQLite';
}
}
# NOTE: It seems to be better to compare rounded values
# because stored coordinate values may have slight errors
@ -53,15 +52,6 @@ my @test_results = (
[1, 3, 5, 6]
);
BEGIN {
if (!grep /ENABLE_RTREE/, DBD::SQLite::compile_options()) {
plan skip_all => 'RTREE is disabled for this DBD::SQLite';
}
}
use Test::NoWarnings;
plan tests => @coords + (2 * @test_regions) + 4;
# connect
my $dbh = connect_ok( RaiseError => 1 );
@ -112,3 +102,5 @@ for my $region (@test_regions) {
my $results = $dbh->selectcol_arrayref($overlap_sql, undef, @$region);
is_deeply_approx($results, shift @test_results);
}
done_testing;

View file

@ -1,20 +1,12 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
use if -d ".git", "Test::FailWarnings";
BEGIN { requires_sqlite('3.6.8') }
plan tests => 5;
use Test::NoWarnings;
my $dbh = connect_ok(
AutoCommit => 1,
RaiseError => 1,
@ -47,3 +39,5 @@ is $dbh->selectrow_array("SELECT COUNT(*) FROM MST"), 0,
"savepoint rolled back";
$dbh->rollback;
done_testing;

View file

@ -1,22 +1,15 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
use if -d ".git", "Test::FailWarnings";
BEGIN {
eval {require APR::Table; 1};
if ($@) {
plan skip_all => 'requires APR::Table';
}
else {
plan tests => 2;
}
}
my $dbh = connect_ok(
@ -27,3 +20,5 @@ my $dbh = connect_ok(
eval { $dbh->do('SELECT 1') };
ok !$@, "no errors";
diag $@ if $@;
done_testing;

View file

@ -1,19 +1,11 @@
#!/usr/bin/perl
# Trigger locking error and test prepared statement is still valid afterwards
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok dbfile @CALL_FUNCS/;
use Test::More;
use Test::NoWarnings;
plan tests => 10 * @CALL_FUNCS + 1;
use if -d ".git", "Test::FailWarnings";
foreach my $call_func (@CALL_FUNCS) {
@ -83,3 +75,5 @@ foreach my $call_func (@CALL_FUNCS) {
unlink $dbfile;
}
done_testing;

View file

@ -1,20 +1,12 @@
#!/usr/bin/perl
# Check data type assignment in bind_param is sticky
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok/;
use DBI qw(:sql_types);
use Test::More;
use Test::NoWarnings;
plan tests => 10 + 1;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok(
RaiseError => 1,
@ -47,3 +39,5 @@ $dbh->commit;
$dbh->disconnect;
undef($dbh);
done_testing;

View file

@ -1,20 +1,12 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS requires_sqlite/;
use Test::More;
BEGIN { requires_sqlite('3.6.21') }
use Test::NoWarnings;
plan tests => 12 * @CALL_FUNCS + 1;
use if -d ".git", "Test::FailWarnings";
my $flag = 0;
for my $call_func (@CALL_FUNCS) {
@ -63,3 +55,5 @@ for my $call_func (@CALL_FUNCS) {
is $profile[2][0] => "insert into bar values (?)";
like $profile[2][1] => qr/^[0-9]+$/;
}
done_testing;

24
t/50_foreign_key_info.t Executable file → Normal file
View file

@ -1,11 +1,5 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
@ -18,7 +12,7 @@ BEGIN {
}
}
use Test::NoWarnings;
use if -d ".git", "Test::FailWarnings";
# SQL below freely adapted from http://www.sqlite.org/foreignkeys.htm ...
# not the best datamodel in the world, but good enough for our tests.
@ -42,7 +36,7 @@ ATTACH DATABASE ':memory:' AS remote;
CREATE TABLE remote.album (
albumartist INTEGER NOT NULL REFERENCES artist(artistid)
ON DELETE RESTRICT
ON UPDATE CASCADE,
ON UPDATE CASCADE DEFERRABLE,
albumname TEXT,
albumcover BINARY,
albumeditor INTEGER NOT NULL REFERENCES editor(editorid),
@ -58,9 +52,6 @@ CREATE TABLE song(
);
__EOSQL__
plan tests => @sql_statements + 20;
my $dbh = connect_ok( RaiseError => 1, PrintError => 0, AutoCommit => 1 );
my $sth;
my $fk_data;
@ -78,6 +69,7 @@ for ($fk_data->{albumartist}) {
is($_->{KEY_SEQ}, 1, "FK albumartist, key seq");
is($_->{DELETE_RULE}, $R->{RESTRICT}, "FK albumartist, delete rule");
is($_->{UPDATE_RULE}, $R->{CASCADE}, "FK albumartist, update rule");
is($_->{DEFERRABILITY}, $R->{'INITIALLY IMMEDIATE'}, "FK albumartist, deferrability");
is($_->{UNIQUE_OR_PRIMARY}, 'UNIQUE', "FK albumartist, unique");
}
for ($fk_data->{albumeditor}) {
@ -87,34 +79,30 @@ for ($fk_data->{albumeditor}) {
# rules are 'NO ACTION' by default
is($_->{DELETE_RULE}, $R->{'NO ACTION'}, "FK albumeditor, delete rule");
is($_->{UPDATE_RULE}, $R->{'NO ACTION'}, "FK albumeditor, update rule");
is($_->{DEFERRABILITY}, $R->{'NOT DEFERRABLE'}, "FK albumeditor, deferrability");
is($_->{UNIQUE_OR_PRIMARY}, 'PRIMARY', "FK albumeditor, primary");
}
$sth = $dbh->foreign_key_info(undef, undef, 'artist',
undef, undef, 'album');
$fk_data = $sth->fetchall_hashref('FKCOLUMN_NAME');
is_deeply([keys %$fk_data], ['albumartist'], "FK album with PK, only 1 result");
$sth = $dbh->foreign_key_info(undef, undef, 'foobar',
undef, undef, 'album');
$fk_data = $sth->fetchall_hashref('FKCOLUMN_NAME');
is_deeply([keys %$fk_data], [], "FK album with PK foobar, 0 result");
$sth = $dbh->foreign_key_info(undef, undef, undef,
undef, 'remote', undef);
$fk_data = $sth->fetchall_hashref('FKCOLUMN_NAME');
is_deeply([sort keys %$fk_data], [qw/albumartist albumeditor/], "FK remote.*, 2 results");
$sth = $dbh->foreign_key_info(undef, 'remote', undef,
undef, undef, undef);
$fk_data = $sth->fetchall_hashref('FKCOLUMN_NAME');
is_deeply([sort keys %$fk_data], [qw/songalbum songartist/], "FK with PK remote.*, 2 results");
$sth = $dbh->foreign_key_info(undef, undef, undef,
undef, undef, 'song');
$fk_data = $sth->fetchall_hashref('FKCOLUMN_NAME');
@ -124,3 +112,5 @@ for ($fk_data->{songartist}) {
for ($fk_data->{songalbum}) {
is($_->{KEY_SEQ}, 2, "FK song, key seq 2");
}
done_testing;

View file

@ -1,25 +1,16 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use DBD::SQLite;
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
use if -d ".git", "Test::FailWarnings";
BEGIN {
if (!grep /^ENABLE_COLUMN_METADATA/, DBD::SQLite::compile_options()) {
if (!has_compile_option('ENABLE_COLUMN_METADATA')) {
plan skip_all => "Column metadata is disabled for this DBD::SQLite";
}
}
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS/;
use Test::NoWarnings;
plan tests => 16 * @CALL_FUNCS + 1;
for my $call_func (@CALL_FUNCS) {
my $dbh = connect_ok(RaiseError => 1);
$dbh->do('create table foo (id integer primary key autoincrement, "name space", unique_col integer unique)');
@ -63,3 +54,5 @@ for my $call_func (@CALL_FUNCS) {
ok $@, "successfully died when dbh is inactive";
}
}
done_testing;

View file

@ -1,20 +1,12 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS requires_sqlite/;
use Test::More;
BEGIN { requires_sqlite('3.7.10') }
use Test::NoWarnings;
plan tests => 6 * @CALL_FUNCS + 1;
use if -d ".git", "Test::FailWarnings";
for my $func (@CALL_FUNCS) {
{
@ -39,3 +31,5 @@ sub filename {
my $dbh = connect_ok(@_);
$dbh->$func('db_filename');
}
done_testing;

View file

@ -1,21 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS has_sqlite/;
use Test::More;
use Test::NoWarnings;
my $tests = 3;
$tests += 2 if has_sqlite('3.6.4');
$tests += 1 if has_sqlite('3.7.0');
plan tests => 4 + $tests * @CALL_FUNCS + 1;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok();
{
@ -58,3 +46,5 @@ for my $func (@CALL_FUNCS) {
}
}
}
done_testing;

View file

@ -1,15 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok/;
use Test::More tests => 5;
use Test::NoWarnings;
use Test::More;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok();
@ -27,3 +21,5 @@ $dbh->do("\nCOMMIT");
is $dbh->{AutoCommit}, 1,
'AutoCommit=1 after "\nCOMMIT"';
done_testing;

View file

@ -1,11 +1,5 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
@ -18,7 +12,7 @@ BEGIN {
}
}
use Test::NoWarnings;
use if -d ".git", "Test::FailWarnings";
my @sql_statements = split /\n\n/, <<__EOSQL__;
CREATE TABLE a (
@ -46,9 +40,6 @@ CREATE TABLE remote.b (
__EOSQL__
plan tests => @sql_statements + 2 + 46 * 2;
my $dbh = connect_ok( RaiseError => 1, PrintError => 0, AutoCommit => 1 );
my $sth;
my $stats_data;
@ -123,3 +114,5 @@ for my $table_name ('a', 'A') {
}
ok(not(exists $stats_data->{a_ln}->{3}), "only two indexes in a_an index");
}
done_testing;

View file

@ -1,19 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
my $tests = 7;
$tests += 1 if has_sqlite('3.7.7');
plan tests => $tests;
use if -d ".git", "Test::FailWarnings";
use DBI;
use DBD::SQLite;
@ -111,3 +101,5 @@ if (has_sqlite('3.7.7')) {
$dbh->disconnect;
unlink $dbfile if -f $dbfile;
}
done_testing;

View file

@ -1,18 +1,12 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
use if -d ".git", "Test::FailWarnings";
BEGIN { requires_sqlite('3.7.7') }
plan tests => 17;
use DBI;
use DBD::SQLite;
@ -34,7 +28,8 @@ sub cleanup {
cleanup();
{
SKIP: {
skip 'URI filename is enabled', 1 if has_compile_option('USE_URI');
my $dbh = eval {
DBI->connect("dbi:SQLite:$uri{base}", undef, undef, {
PrintError => 0,
@ -225,3 +220,5 @@ cleanup();
$dbh->disconnect;
cleanup();
}
done_testing;

View file

@ -1,19 +1,11 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok/;
use Test::More;
use Test::NoWarnings;
use if -d ".git", "Test::FailWarnings";
use DBI qw(:sql_types);
plan tests => 9;
# The following is by mje++
# http://pastebin.com/RkUwwVti
@ -72,3 +64,5 @@ $sth->bind_param(1, 1, SQL_INTEGER);
$sth->bind_param(2, $test_value, SQL_VARCHAR);
$sth->execute;
my_is($dbh, "prepared insert with provided bound data and type SQL_VARCHAR see_if_its_a_number=0");
done_testing;

View file

@ -1,11 +1,5 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok/;
use Test::More;
@ -16,12 +10,10 @@ BEGIN{
plan skip_all => 'this test requires SQLite 3.7.12 and above' unless $DBD::SQLite::sqlite_version_number > 3007011;
}
use Test::NoWarnings;
use if -d ".git", "Test::FailWarnings";
use DBD::SQLite::Constants qw/:extended_result_codes :result_codes/;
use File::Temp;
plan tests => 18;
my $tmpdir = File::Temp::tempdir(CLEANUP => 1);
ok -d $tmpdir;
@ -56,3 +48,5 @@ for my $flag (0, 1) {
my $err = DBI->err;
is $err => $expected{$flag};
}
done_testing;

View file

@ -1,11 +1,5 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok requires_sqlite/;
use Test::More;
@ -13,9 +7,7 @@ use DBD::SQLite::Constants qw/SQLITE_OPEN_READONLY/;
BEGIN { requires_sqlite('3.7.11') }
use Test::NoWarnings;
plan tests => 14;
use if -d ".git", "Test::FailWarnings";
{
my $dbh = connect_ok(
@ -46,3 +38,5 @@ plan tests => 14;
# told so)
ok $dbh->do('CREATE TABLE foo (id)');
}
done_testing;

View file

@ -1,11 +1,5 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/requires_sqlite/;
use Test::More;
@ -13,9 +7,7 @@ use DBD::SQLite;
BEGIN { requires_sqlite('3.10.0'); }
use Test::NoWarnings;
plan tests => 13;
use if -d ".git", "Test::FailWarnings";
ok !DBD::SQLite::strlike("foo_bar", "FOO1BAR");
ok !DBD::SQLite::strlike("foo_bar", "FOO_BAR");
@ -29,3 +21,5 @@ ok DBD::SQLite::strlike("\\%foobar", "1FOOBAR", "\\");
ok !DBD::SQLite::strlike("\\%foobar", "%FOOBAR", "\\");
ok DBD::SQLite::strlike("!%foobar", "1FOOBAR", "!");
ok !DBD::SQLite::strlike("!%foobar", "%FOOBAR", "!");
done_testing;

View file

@ -1,20 +1,13 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS/;
use SQLiteTest;
use Test::More;
BEGIN {
if ($] < 5.008005) {
plan skip_all => 'Unicode is not supported before 5.8.5';
}
}
#use Test::NoWarnings; # see RT#112220
#use if -d ".git", "Test::FailWarnings"; # see RT#112220
BEGIN { requires_unicode_support() }
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
# special case for multibyte (non-ASCII) character class,
# which only works correctly under the unicode mode
@ -22,19 +15,17 @@ my @words = ("\x{e3}\x{83}\x{86}\x{e3}\x{82}\x{b9}\x{e3}\x{83}\x{88}", "\x{e3}\x
my $regex = "\x{e3}\x{83}\x{86}[\x{e3}\x{82}\x{b9}\x{e3}\x{83}\x{b3}]\x{e3}\x{83}\x{88}"; # テ[スン]ト
plan tests => 2 * 2 * @CALL_FUNCS;
foreach my $call_func (@CALL_FUNCS) {
for my $use_unicode (0, 1) {
for my $string_mode (DBD_SQLITE_STRING_MODE_PV, DBD_SQLITE_STRING_MODE_UNICODE_STRICT) {
# connect
my $dbh = connect_ok( RaiseError => 1, sqlite_unicode => $use_unicode );
my $dbh = connect_ok( RaiseError => 1, sqlite_string_mode => $string_mode );
# populate test data
my @vals = @words;
my $re = $regex;
if ($use_unicode) {
if ($string_mode == DBD_SQLITE_STRING_MODE_UNICODE_STRICT) {
utf8::decode($_) foreach @vals;
utf8::decode($re);
}
@ -52,3 +43,4 @@ foreach my $call_func (@CALL_FUNCS) {
}
}
done_testing;

View file

@ -1,17 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok/;
use Test::More;
use Test::NoWarnings;
plan tests => 7;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok( RaiseError => 1 );
ok $dbh->do('create table foo (id integer, value integer)');
@ -34,3 +26,5 @@ ok $dbh->do('create table foo (id integer, value integer)');
my $sth = $dbh->prepare('select * from foo where id = ?');
is_deeply $sth->{ParamValues} => {1 => undef}, "ParamValues without binding";
}
done_testing;

25
t/64_limit.t Normal file
View file

@ -0,0 +1,25 @@
use strict;
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS/;
use Test::More;
use DBD::SQLite::Constants qw/SQLITE_LIMIT_VARIABLE_NUMBER/;
use if -d ".git", "Test::FailWarnings";
for my $func (@CALL_FUNCS) {
my $dbh = connect_ok(PrintError => 0, RaiseError => 1);
my $current_limit = $dbh->$func(SQLITE_LIMIT_VARIABLE_NUMBER, 'limit');
ok $current_limit, "current limit: $current_limit";
$current_limit = $dbh->$func(SQLITE_LIMIT_VARIABLE_NUMBER, -1, 'limit');
ok $current_limit, "current limit: $current_limit";
ok $dbh->do('create table foo (id, text)');
ok $dbh->do('insert into foo values(?, ?)', undef, 1, 'OK');
ok $dbh->$func(SQLITE_LIMIT_VARIABLE_NUMBER, 1, 'limit');
eval { $dbh->do('insert into foo values(?, ?)', undef, 2, 'NOT OK') };
like $@ => qr/too many SQL variables/, "should raise error because of the variable limit";
}
done_testing;

313
t/65_db_config.t Normal file
View file

@ -0,0 +1,313 @@
use strict;
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS/;
use Test::More;
use DBD::SQLite::Constants qw/:database_connection_configuration_options/;
use if -d ".git", "Test::FailWarnings";
# LOOKASIDE
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'LOOKASIDE is not supported', 2 if !SQLITE_DBCONFIG_LOOKASIDE;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
eval { $dbh->$func(SQLITE_DBCONFIG_LOOKASIDE, 1, 'db_config') };
ok $@, 'LOOKASIDE is not supported';
like $@ => qr/LOOKASIDE is not supported/;
}
}
# MAINDBNAME
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'MAINDBNAME is not supported', 2 if !SQLITE_DBCONFIG_MAINDBNAME;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
eval { $dbh->$func(SQLITE_DBCONFIG_MAINDBNAME, 1, 'db_config') };
ok $@, 'MAINDBNAME is not supported';
like $@ => qr/MAINDBNAME is not supported/;
}
}
# ENABLE_FKEY
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'ENABLE_FKEY is not supported', 3 if !SQLITE_DBCONFIG_ENABLE_FKEY;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
my $ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_FKEY, -1, 'db_config');
note "current ENABLE_FKEY value: $ret";
$ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_FKEY, 1, 'db_config');
is $ret => 1, 'enable foreign key';
# TODO: add foreign key check
$ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_FKEY, 0, 'db_config');
is $ret => 0, 'disable foreign key';
}
}
# ENABLE_TRIGGER
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'ENABLE_TRIGGER is not supported', 3 if !SQLITE_DBCONFIG_ENABLE_TRIGGER;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
my $ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_TRIGGER, -1, 'db_config');
note "current ENABLE_TRIGGER value: $ret";
$ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_TRIGGER, 1, 'db_config');
is $ret => 1, 'enable trigger';
# TODO: add trigger check
$ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_TRIGGER, 0, 'db_config');
is $ret => 0, 'disable trigger';
}
}
# ENABLE_FTS3_TOKENIZER
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'ENABLE_FTS3_TOKENIZER is not supported', 3 if !SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
my $ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, -1, 'db_config');
note "current ENABLE_FTS3_TOKENIZER value: $ret";
$ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 'db_config');
is $ret => 1, 'enable fts3_tokenizer';
# TODO: add fts3_tokenizer check
$ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 0, 'db_config');
is $ret => 0, 'disable fts3_tokenizer';
}
}
# ENABLE_LOAD_EXTENSION
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'ENABLE_LOAD_EXTENSION is not supported', 3 if !SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
my $ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, -1, 'db_config');
note "current ENABLE_LOAD_EXTENSION value: $ret";
$ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, 'db_config');
is $ret => 1, 'enable load_extension';
# TODO: add load_extension check
$ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 0, 'db_config');
is $ret => 0, 'disable load_extension';
}
}
# NO_CKPT_ON_CLOSE
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'NO_CKPT_ON_CLOSE is not supported', 3 if !SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
my $ret = $dbh->$func(SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, -1, 'db_config');
note "current NO_CKPT_ON_CLOSE value: $ret";
$ret = $dbh->$func(SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, 1, 'db_config');
is $ret => 1, 'no checkpoint on close';
# TODO: add checkpoint check
$ret = $dbh->$func(SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, 0, 'db_config');
is $ret => 0, 'checkpoint on close';
}
}
# ENABLE_QPSG
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'ENABLE_QPSG is not supported', 3 if !SQLITE_DBCONFIG_ENABLE_QPSG;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
my $ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_QPSG, -1, 'db_config');
note "current ENABLE_OPSG value: $ret";
$ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_QPSG, 1, 'db_config');
is $ret => 1, 'enable query planner stability guarantee';
# TODO: add qpsg check
$ret = $dbh->$func(SQLITE_DBCONFIG_ENABLE_QPSG, 0, 'db_config');
is $ret => 0, 'disable query planner stability guarantee';
}
}
# TRIGGER_EQP
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'TRIGGER_EQP is not supported', 3 if !SQLITE_DBCONFIG_TRIGGER_EQP;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
my $ret = $dbh->$func(SQLITE_DBCONFIG_TRIGGER_EQP, -1, 'db_config');
note "current TRIGGER_EQP value: $ret";
$ret = $dbh->$func(SQLITE_DBCONFIG_TRIGGER_EQP, 1, 'db_config');
is $ret => 1, 'trigger explain query plan';
# TODO: add trigger check
$ret = $dbh->$func(SQLITE_DBCONFIG_TRIGGER_EQP, 0, 'db_config');
is $ret => 0, 'no trigger explain query plan';
}
}
# RESET_DATABASE
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'RESET_DATABASE is not supported', 3 if !SQLITE_DBCONFIG_RESET_DATABASE;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
my $ret = $dbh->$func(SQLITE_DBCONFIG_RESET_DATABASE, -1, 'db_config');
note "current RESET_DATABASE value: $ret";
$ret = $dbh->$func(SQLITE_DBCONFIG_RESET_DATABASE, 1, 'db_config');
is $ret => 1, 'enable reset database';
# TODO: add reset check
$ret = $dbh->$func(SQLITE_DBCONFIG_RESET_DATABASE, 0, 'db_config');
is $ret => 0, 'disable reset database';
}
}
# DEFENSIVE
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'DEFENSIVE is not supported', 8 if !SQLITE_DBCONFIG_DEFENSIVE;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
my $sql = 'CREATE TABLE foo (id, text)';
$dbh->do($sql);
$dbh->do('PRAGMA writable_schema=ON');
my $row = $dbh->selectrow_hashref('SELECT * FROM sqlite_master WHERE name = ?', {Slice => +{}}, 'foo');
is $row->{sql} => $sql, 'found sql';
my $ret = $dbh->$func(SQLITE_DBCONFIG_DEFENSIVE, -1, 'db_config');
note "current DEFENSIVE value: $ret";
$ret = $dbh->$func(SQLITE_DBCONFIG_DEFENSIVE, 1, 'db_config');
is $ret => 1;
eval { $dbh->do('UPDATE sqlite_master SET name = ? WHERE name = ?', undef, 'bar', 'foo'); };
ok $@, "updating sqlite_master is prohibited";
like $@ => qr/table sqlite_master may not be modified/;
$ret = $dbh->$func(SQLITE_DBCONFIG_DEFENSIVE, 0, 'db_config');
is $ret => 0;
$ret = $dbh->do('UPDATE sqlite_master SET name = ? WHERE name = ?', undef, 'bar', 'foo');
ok $ret, 'updating sqlite_master is succeeded';
$row = $dbh->selectrow_hashref('SELECT * FROM sqlite_master WHERE name = ?', {Slice => +{}}, 'foo');
ok !$row, 'sql not found';
}
}
# DEFENSIVE at connection
SKIP: {
skip 'DEFENSIVE is not supported', 3 if !SQLITE_DBCONFIG_DEFENSIVE;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0, sqlite_defensive => 1);
my $sql = 'CREATE TABLE foo (id, text)';
$dbh->do($sql);
$dbh->do('PRAGMA writable_schema=ON');
eval { $dbh->do('UPDATE sqlite_master SET name = ? WHERE name = ?', undef, 'bar', 'foo'); };
ok $@, "updating sqlite_master is prohibited";
like $@ => qr/table sqlite_master may not be modified/;
}
# WRITABLE_SCHEMA
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'WRITABLE_SCHEMA is not supported', 5 if !SQLITE_DBCONFIG_WRITABLE_SCHEMA;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
my $ret = $dbh->$func(SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, 'db_config');
note "current WRITABLE_SCHEMA value: $ret";
$ret = $dbh->$func(SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 'db_config');
is $ret => 1, 'schema is writable';
$ret = $dbh->$func(SQLITE_DBCONFIG_WRITABLE_SCHEMA, 0, 'db_config');
is $ret => 0, 'schema is not writable';
$dbh->do('PRAGMA writable_schema=ON');
$ret = $dbh->$func(SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, 'db_config');
is $ret => 1, 'schema is writable (by pragma)';
$dbh->do('PRAGMA writable_schema=OFF');
$ret = $dbh->$func(SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, 'db_config');
is $ret => 0, 'schema is not writable (by pragma)';
}
}
# LEGACY_ALTER_TABLE
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'WRITABLE_SCHEMA is not supported', 5 if !SQLITE_DBCONFIG_LEGACY_ALTER_TABLE;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
my $ret = $dbh->$func(SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, -1, 'db_config');
note "current LEGACY_ALTER_TABLE value: $ret";
$ret = $dbh->$func(SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, 1, 'db_config');
is $ret => 1, 'use legacy alter table';
$ret = $dbh->$func(SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, 0, 'db_config');
is $ret => 0, 'no legacy alter table';
# TODO: add alter table check?
$dbh->do('PRAGMA legacy_alter_table=ON');
$ret = $dbh->$func(SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, -1, 'db_config');
is $ret => 1, 'use legacy alter table (by pragma)';
$dbh->do('PRAGMA legacy_alter_table=OFF');
$ret = $dbh->$func(SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, -1, 'db_config');
is $ret => 0, 'no legacy alter table (by pragma)';
}
}
# DQS_DML
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'DQS_DML is not supported', 5 if !SQLITE_DBCONFIG_DQS_DML;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
my $ret = $dbh->$func(SQLITE_DBCONFIG_DQS_DML, -1, 'db_config');
note "current DQS_DML value: $ret";
$dbh->do('CREATE TABLE foo (id, text)');
$ret = $dbh->$func(SQLITE_DBCONFIG_DQS_DML, 1, 'db_config');
is $ret => 1, 'allows double-quoted string literal';
eval { $dbh->do('INSERT INTO foo VALUES (1, "text")'); };
ok !$@, "double-quoted string literal is allowed";
$ret = $dbh->$func(SQLITE_DBCONFIG_DQS_DML, 0, 'db_config');
is $ret => 0, 'no double-quoted string literal';
eval { $dbh->do('INSERT INTO foo VALUES (2, "text2")'); };
like $@ => qr/no such column/, "double-quoted string literal is not allowed";
}
}
# DQS_DDL
for my $func (@CALL_FUNCS) {
SKIP: {
skip 'DQS_DDL is not supported', 5 if !SQLITE_DBCONFIG_DQS_DDL;
my $dbh = connect_ok(RaiseError => 1, PrintError => 0);
my $ret = $dbh->$func(SQLITE_DBCONFIG_DQS_DDL, -1, 'db_config');
note "current DQS_DDL value: $ret";
$ret = $dbh->$func(SQLITE_DBCONFIG_DQS_DDL, 1, 'db_config');
is $ret => 1, 'allows double-quoted string literal';
eval { $dbh->do('CREATE TABLE foo (a, b, c CHECK (c!="null") )'); };
ok !$@, "double-quoted string literal is allowed";
$ret = $dbh->$func(SQLITE_DBCONFIG_DQS_DDL, 0, 'db_config');
is $ret => 0, 'no double-quoted string literal';
eval { $dbh->do('CREATE TABLE bar (a, b, c CHECK (c!="null") )'); };
like $@ => qr/no such column/, "double-quoted string literal is not allowed";
}
}
done_testing;

57
t/66_get_autocommit.t Normal file
View file

@ -0,0 +1,57 @@
use strict;
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS/;
use Test::More;
use if -d ".git", "Test::FailWarnings";
for my $func (@CALL_FUNCS) {
my $dbh = connect_ok(PrintError => 0, RaiseError => 1);
$dbh->do('create table foo (id)');
note 'begin_work does not make autocommit false';
my $autocommit = $dbh->$func('get_autocommit');
ok $autocommit, "internal autocommit is true";
ok $dbh->{AutoCommit}, "AutoCommit is also true";
$dbh->begin_work;
$autocommit = $dbh->$func('get_autocommit');
ok $autocommit, "internal autocommit is still true";
ok !$dbh->{AutoCommit}, "AutoCommit gets false";
$dbh->do('insert into foo values (1)');
$dbh->commit;
$autocommit = $dbh->$func('get_autocommit');
ok $autocommit, "internal autocommit is still true";
ok $dbh->{AutoCommit}, "AutoCommit is true now";
note 'nor turning AutoCommit off does not make autocommit false';
$dbh->{AutoCommit} = 0;
$autocommit = $dbh->$func('get_autocommit');
ok $autocommit, "internal autocommit is still true";
ok !$dbh->{AutoCommit}, "AutoCommit is false";
$dbh->do('insert into foo values (1)');
$dbh->commit;
$dbh->{AutoCommit} = 1;
$autocommit = $dbh->$func('get_autocommit');
ok $autocommit, "internal autocommit is still true";
ok $dbh->{AutoCommit}, "AutoCommit is true now";
note 'explicit BEGIN make autocommit false';
$dbh->do('BEGIN');
$autocommit = $dbh->$func('get_autocommit');
ok !$autocommit, "internal autocommit gets false";
ok !$dbh->{AutoCommit}, "AutoCommit is also false";
$dbh->do('insert into foo values (1)');
$dbh->commit;
$autocommit = $dbh->$func('get_autocommit');
ok $autocommit, "internal autocommit is true now";
ok $dbh->{AutoCommit}, "AutoCommit is true now";
}
done_testing;

41
t/67_txn_state.t Normal file
View file

@ -0,0 +1,41 @@
use strict;
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok @CALL_FUNCS/;
use Test::More;
use if -d ".git", "Test::FailWarnings";
use DBD::SQLite::Constants ':allowed_return_values_from_sqlite3_txn_state';
note "test main schema";
test('main');
note "test undef schema";
test(undef);
note "omit schema";
test();
done_testing;
sub test {
my @schema = @_;
die if @schema > 1;
for my $func (@CALL_FUNCS) {
my $dbh = connect_ok(PrintError => 0, RaiseError => 1);
$dbh->do('create table foo (id)');
my $txn_state = $dbh->$func(@schema, 'txn_state');
is $txn_state => SQLITE_TXN_NONE, "internal transaction is none";
$dbh->do('BEGIN');
my $row = $dbh->selectrow_arrayref('SELECT * FROM foo');
$txn_state = $dbh->$func(@schema, 'txn_state');
is $txn_state => SQLITE_TXN_READ, "internal transaction is read";
$dbh->do('insert into foo values (1)');
$txn_state = $dbh->$func(@schema, 'txn_state');
is $txn_state => SQLITE_TXN_WRITE, "internal transaction is write";
$dbh->commit;
}
}

View file

@ -0,0 +1,63 @@
# This is a test for correct handling of upgraded strings without
# the sqlite_unicode parameter.
use strict;
use warnings;
use lib "t/lib";
use SQLiteTest;
use DBD::SQLite::Constants;
use Test::More;
use if -d ".git", "Test::FailWarnings";
{
my $dbh = connect_ok( dbfile => 'foo', RaiseError => 1 );
$dbh->{sqlite_string_mode} = DBD::SQLite::Constants::DBD_SQLITE_STRING_MODE_BYTES;
my $tbl_name = "\xe9p\xe9e";
utf8::encode $tbl_name;
my $str = "CREATE TABLE $tbl_name ( col1 TEXT )";
utf8::upgrade $str;
$dbh->do($str);
my $master_ar = $dbh->selectall_arrayref('SELECT * FROM sqlite_master', { Slice => {} });
is(
$master_ar->[0]{'name'},
$tbl_name,
'do() takes correct string value',
);
#----------------------------------------------------------------------
my $dummy_str = "SELECT '$tbl_name'";
utf8::upgrade $dummy_str;
my $sth = $dbh->prepare($dummy_str);
$sth->execute();
my $row = $sth->fetchrow_arrayref();
is(
$row->[0],
$tbl_name,
'prepare() takes correct string value',
);
#----------------------------------------------------------------------
my $tbl_name_ug = $tbl_name;
utf8::upgrade $tbl_name_ug;
my $sth2 = $dbh->prepare('SELECT ?');
$sth2->execute( do { my $v = $tbl_name_ug } );
$row = $sth2->fetchrow_arrayref();
is(
$row->[0],
$tbl_name,
'execute() takes correct string value',
);
}
done_testing;

View file

@ -1,17 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
use Test::NoWarnings;
plan tests => 3 * @CALL_FUNCS * 3 + 1;
use if -d ".git", "Test::FailWarnings";
# The following snippets are copied from Cookbook.pod by hand.
# Don't forget to update here when the pod is updated.
@ -132,3 +124,5 @@ END_SQL
is $result->[1] => 1250;
}
}
done_testing;

View file

@ -8,7 +8,11 @@ use File::Spec ();
use Test::More ();
our @ISA = 'Exporter';
our @EXPORT = qw/connect_ok dies dbfile @CALL_FUNCS $sqlite_call has_sqlite requires_sqlite/;
our @EXPORT = qw/
connect_ok dies dbfile @CALL_FUNCS $sqlite_call
has_sqlite requires_sqlite requires_unicode_support
allow_warnings has_compile_option has_fts
/;
our @CALL_FUNCS;
our $sqlite_call;
@ -100,15 +104,6 @@ On more recent versions, the loop will run twice;
the second execution will call
C<< $dbh->sqlite_method_to_call(@args) >>.
The number of tests to plan should be adapted accordingly.
It can be computed like this :
plan tests => $n_normal_tests * @CALL_FUNCS + 1;
The additional C< + 1> is required when using
L<Test::NoWarnings>, because that module adds
a final test in an END block outside of the loop.
=cut
@ -146,6 +141,40 @@ $sqlite_call = sub {
$CALL_FUNCS[-1]->($dbh, @_, $func_to_call);
};
=head2 has_compile_option
has_compile_option('ENABLE_FTS3');
has_compile_option(qr/^ENABLE_FTS[345]/);
returns true if DBD::SQLite is built with a specified compile option.
=cut
sub has_compile_option {
my $option = shift;
require DBD::SQLite;
return unless DBD::SQLite->can('compile_options');
my $re = ref $option eq ref qr// ? $option : qr/\b$option\b/;
grep /$re/, DBD::SQLite::compile_options();
}
=head2 has_fts
has_fts();
has_fts(3);
returns true if DBD::SQLite is built with FTS.
=cut
sub has_fts {
if (my $version = shift) {
has_compile_option("ENABLE_FTS$version");
} else {
has_compile_option(qr/\bENABLE_FTS\d\b/);
}
}
=head2 has_sqlite
has_sqlite('3.6.11');
@ -179,4 +208,33 @@ sub requires_sqlite {
}
}
=head2 requires_unicode_support
BEGIN { requires_unicode_support(); }
skips all the tests if Perl does not have sane Unicode support.
=cut
sub requires_unicode_support {
unless ($] >= 5.008005) {
Test::More::plan skip_all => "Unicode is not supported before 5.8.5";
exit;
}
}
=head2 allow_warnings
allow_warnings { eval {...} };
hides SQLite warnings from Test::FailWarnings.
=cut
sub allow_warnings (&) {
my $code = shift;
local $SIG{__WARN__} = sub { Test::More::note @_ };
$code->();
}
1;

View file

@ -1,20 +1,12 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
use if -d ".git", "Test::FailWarnings";
BEGIN { requires_sqlite('3.6.8') }
plan tests => 13;
use Test::NoWarnings;
{ # simple case
my $dbh = connect_ok(
AutoCommit => 1,
@ -160,3 +152,5 @@ use Test::NoWarnings;
$dbh->{AutoCommit} = 1;
# should not spit the "Issuing rollback()" warning
}
done_testing;

View file

@ -1,20 +1,12 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
use if -d ".git", "Test::FailWarnings";
BEGIN { requires_sqlite('3.6.8') }
plan tests => 2;
use Test::NoWarnings;
{ # simple case
my $dbh = connect_ok(
AutoCommit => 1,
@ -26,3 +18,5 @@ use Test::NoWarnings;
$dbh->commit;
# should not spit the "Issuing rollback()" warning
}
done_testing;

View file

@ -1,17 +1,9 @@
#!/usr/bin/perl
use strict;
BEGIN {
$| = 1;
$^W = 1;
}
use warnings;
use lib "t/lib";
use SQLiteTest;
use Test::More;
plan tests => 14;
use Test::NoWarnings;
use if -d ".git", "Test::FailWarnings";
{
my $dbh = connect_ok();
@ -36,3 +28,5 @@ use Test::NoWarnings;
is $info{bat}[1] => 4;
is $info{bat}[2] => 4;
}
done_testing;

Some files were not shown because too many files have changed in this diff Show more