1
0
Fork 0
mirror of https://github.com/DBD-SQLite/DBD-SQLite synced 2025-06-07 22:28:47 -04:00

Compare commits

..

No commits in common. "master" and "1.67_03" have entirely different histories.

32 changed files with 19392 additions and 44905 deletions

View file

@ -15,18 +15,14 @@ jobs:
strategy: strategy:
matrix: matrix:
perl-version: perl-version:
- '5.8-buster' - '5.8'
- '5.10-buster'
- '5.18-buster'
- '5.20-buster'
- '5.26'
- 'latest' - 'latest'
container: container:
image: perl:${{ matrix.perl-version }} image: perl:${{ matrix.perl-version }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v1
- name: perl -V - name: perl -V
run: perl -V run: perl -V
- name: Install dependencies - name: Install dependencies

82
Changes
View file

@ -1,87 +1,5 @@
Changes for Perl extension DBD-SQLite 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 1.67_03 2021-03-31
- Upgraded SQLite to 3.35.3 - Upgraded SQLite to 3.35.3
- Enabled math functions introduced in SQLite 3.35 - Enabled math functions introduced in SQLite 3.35

View file

@ -262,7 +262,7 @@ if ( $^O eq 'cygwin') {
if ( $Config{d_usleep} || $Config{osname} =~ m/linux/ ) { if ( $Config{d_usleep} || $Config{osname} =~ m/linux/ ) {
push @CC_DEFINE, '-DHAVE_USLEEP=1'; push @CC_DEFINE, '-DHAVE_USLEEP=1';
} }
if ( !$Config{usethreads} and $Config{libs} !~ /pthread/ ) { unless ( $Config{usethreads} ) {
push @CC_DEFINE, '-DTHREADSAFE=0'; push @CC_DEFINE, '-DTHREADSAFE=0';
} }
if ($^O eq 'hpux' and $Config{osvers} <= 10.20) { if ($^O eq 'hpux' and $Config{osvers} <= 10.20) {
@ -288,18 +288,8 @@ if ($^O =~ /bsd/i && $^O !~ /(?:open|net)bsd/) {
push @CC_DEFINE, '-D_XOPEN_SOURCE'; push @CC_DEFINE, '-D_XOPEN_SOURCE';
} }
if (!$Config{usedl}) {
push @CC_DEFINE, '-DSQLITE_OMIT_LOAD_EXTENSION';
}
my (@CCFLAGS, @LDFLAGS, @LDDLFLAGS); 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; # RT #70135: See if ld supports Bsymbolic;
unless ($^O eq 'MSWin32' && $Config{ld} =~ /link/) { unless ($^O eq 'MSWin32' && $Config{ld} =~ /link/) {
for my $path (File::Spec->path) { for my $path (File::Spec->path) {
@ -404,9 +394,6 @@ WriteMakefile(
? '$(O_FILES)' ? '$(O_FILES)'
: 'SQLite.o dbdimp.o' : 'SQLite.o dbdimp.o'
), ),
depend => {
'dbdimp.o' => 'dbdimp_tokenizer.inc dbdimp_virtual_table.inc',
},
clean => { clean => {
FILES => 'SQLite.xsi config.h tv.log *.old', FILES => 'SQLite.xsi config.h tv.log *.old',
}, },

View file

@ -391,24 +391,6 @@ txn_state(SV* dbh, SV *schema = &PL_sv_undef)
OUTPUT: OUTPUT:
RETVAL 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 MODULE = DBD::SQLite PACKAGE = DBD::SQLite::st
PROTOTYPES: DISABLE PROTOTYPES: DISABLE

View file

@ -5,13 +5,6 @@ MODULE = DBD::SQLite PACKAGE = DBD::SQLite::Constants
PROTOTYPES: ENABLE 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 #if SQLITE_VERSION_NUMBER >= 3034000
IV IV
@ -493,32 +486,6 @@ _const_database_connection_configuration_options_3031000_zero()
#endif #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 #if SQLITE_VERSION_NUMBER >= 3006002
IV IV
@ -1215,78 +1182,6 @@ _const_extended_result_codes_3034000_zero()
#endif #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 IV
_const_flags_for_file_open_operations() _const_flags_for_file_open_operations()
ALIAS: ALIAS:
@ -1445,30 +1340,6 @@ _const_flags_for_file_open_operations_3033000_zero()
#endif #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 #if SQLITE_VERSION_NUMBER >= 3008003
IV IV
@ -1543,30 +1414,6 @@ _const_function_flags_3031000_zero()
#endif #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 IV
_const_fundamental_datatypes() _const_fundamental_datatypes()
ALIAS: ALIAS:
@ -1574,7 +1421,6 @@ _const_fundamental_datatypes()
SQLITE_FLOAT = SQLITE_FLOAT SQLITE_FLOAT = SQLITE_FLOAT
SQLITE_BLOB = SQLITE_BLOB SQLITE_BLOB = SQLITE_BLOB
SQLITE_NULL = SQLITE_NULL SQLITE_NULL = SQLITE_NULL
SQLITE_TEXT = SQLITE_TEXT
CODE: CODE:
RETVAL = ix; RETVAL = ix;
OUTPUT: OUTPUT:
@ -1972,27 +1818,3 @@ _const__flags_for_file_open_operations_3033000_zero()
#endif #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

342
dbdimp.c
View file

@ -239,11 +239,11 @@ void
init_cxt() { init_cxt() {
dTHX; dTHX;
MY_CXT_INIT; MY_CXT_INIT;
MY_CXT.last_dbh_string_mode = DBD_SQLITE_STRING_MODE_PV; MY_CXT.last_dbh_is_unicode = 0;
} }
SV * SV *
stacked_sv_from_sqlite3_value(pTHX_ sqlite3_value *value, dbd_sqlite_string_mode_t string_mode) stacked_sv_from_sqlite3_value(pTHX_ sqlite3_value *value, int is_unicode)
{ {
STRLEN len; STRLEN len;
sqlite_int64 iv; sqlite_int64 iv;
@ -271,7 +271,9 @@ stacked_sv_from_sqlite3_value(pTHX_ sqlite3_value *value, dbd_sqlite_string_mode
case SQLITE_TEXT: case SQLITE_TEXT:
len = sqlite3_value_bytes(value); len = sqlite3_value_bytes(value);
sv = newSVpvn((const char *)sqlite3_value_text(value), len); sv = newSVpvn((const char *)sqlite3_value_text(value), len);
DBD_SQLITE_UTF8_DECODE_IF_NEEDED(sv, string_mode); if (is_unicode) {
SvUTF8_on(sv);
}
return sv_2mortal(sv); return sv_2mortal(sv);
case SQLITE_BLOB: case SQLITE_BLOB:
len = sqlite3_value_bytes(value); len = sqlite3_value_bytes(value);
@ -405,18 +407,8 @@ sqlite_is_number(pTHX_ const char *v, int sql_type)
if (!_sqlite_atoi64(v, &iv)) return 1; if (!_sqlite_atoi64(v, &iv)) return 1;
} }
if (sql_type != SQLITE_INTEGER) { if (sql_type != SQLITE_INTEGER) {
#ifdef USE_QUADMATH sprintf(format, (has_plus ? "+%%.%d" NVff : "%%.%d" NVff), precision);
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; 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; return 0;
} }
@ -439,44 +431,6 @@ sqlite_discon_all(SV *drh, imp_drh_t *imp_drh)
return FALSE; /* no way to do this */ 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 int
sqlite_db_login6(SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *user, char *pass, SV *attr) sqlite_db_login6(SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *user, char *pass, SV *attr)
{ {
@ -486,7 +440,7 @@ sqlite_db_login6(SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *user, char *pa
SV **val; SV **val;
int extended = 0; int extended = 0;
int flag = 0; int flag = 0;
dbd_sqlite_string_mode_t string_mode = DBD_SQLITE_STRING_MODE_PV; int unicode = 0;
sqlite_trace(dbh, imp_dbh, 3, form("login '%s' (version %s)", dbname, sqlite3_version)); sqlite_trace(dbh, imp_dbh, 3, form("login '%s' (version %s)", dbname, sqlite3_version));
@ -509,24 +463,13 @@ sqlite_db_login6(SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *user, char *pa
hv_stores(hv, "ReadOnly", newSViv(1)); hv_stores(hv, "ReadOnly", newSViv(1));
} }
} }
/* sqlite_unicode should be detected earlier, to register default functions correctly */
/* sqlite_string_mode should be detected earlier, to register default functions correctly */ if (hv_exists(hv, "sqlite_unicode", 14)) {
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); val = hv_fetch(hv, "sqlite_unicode", 14, 0);
if ( (val && SvOK(*val)) ? SvIV(*val) : 0 ) { unicode = (val && SvOK(*val)) ? SvIV(*val) : 0;
string_mode = DBD_SQLITE_STRING_MODE_UNICODE_NAIVE;
}
} else if (hv_exists(hv, "unicode", 7)) { } else if (hv_exists(hv, "unicode", 7)) {
val = hv_fetch(hv, "unicode", 7, 0); val = hv_fetch(hv, "unicode", 7, 0);
if ( (val && SvOK(*val)) ? SvIV(*val) : 0 ) { unicode = (val && SvOK(*val)) ? SvIV(*val) : 0;
string_mode = DBD_SQLITE_STRING_MODE_UNICODE_NAIVE;
}
} }
} }
rc = sqlite_open2(dbname, &(imp_dbh->db), flag, extended); rc = sqlite_open2(dbname, &(imp_dbh->db), flag, extended);
@ -535,7 +478,7 @@ sqlite_db_login6(SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *user, char *pa
} }
DBIc_IMPSET_on(imp_dbh); DBIc_IMPSET_on(imp_dbh);
imp_dbh->string_mode = string_mode; imp_dbh->unicode = unicode;
imp_dbh->functions = newAV(); imp_dbh->functions = newAV();
imp_dbh->aggregates = newAV(); imp_dbh->aggregates = newAV();
imp_dbh->collation_needed_callback = newSVsv( &PL_sv_undef ); imp_dbh->collation_needed_callback = newSVsv( &PL_sv_undef );
@ -603,7 +546,9 @@ sqlite_db_do_sv(SV *dbh, imp_dbh_t *imp_dbh, SV *sv_statement)
} }
/* sqlite3_prepare wants an utf8-encoded SQL statement */ /* sqlite3_prepare wants an utf8-encoded SQL statement */
DBD_SQLITE_PREP_SV_FOR_SQLITE(sv_statement, imp_dbh->string_mode); if (imp_dbh->unicode) {
sv_utf8_upgrade(sv_statement);
}
statement = SvPV_nolen(sv_statement); statement = SvPV_nolen(sv_statement);
@ -790,10 +735,6 @@ sqlite_db_destroy(SV *dbh, imp_dbh_t *imp_dbh)
DBIc_IMPSET_off(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 int
sqlite_db_STORE_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv, SV *valuesv) sqlite_db_STORE_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv, SV *valuesv)
{ {
@ -846,44 +787,26 @@ sqlite_db_STORE_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv, SV *valuesv)
imp_dbh->prefer_numeric_type = !(! SvTRUE(valuesv)); imp_dbh->prefer_numeric_type = !(! SvTRUE(valuesv));
return TRUE; 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")) { 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 #if PERL_UNICODE_DOES_NOT_WORK_WELL
sqlite_trace(dbh, imp_dbh, 3, form("Unicode support is disabled for this version of perl.")); sqlite_trace(dbh, imp_dbh, 3, form("Unicode support is disabled for this version of perl."));
imp_dbh->string_mode = DBD_SQLITE_STRING_MODE_PV; imp_dbh->unicode = 0;
#else #else
imp_dbh->string_mode = SvTRUE(valuesv) ? DBD_SQLITE_STRING_MODE_UNICODE_NAIVE : DBD_SQLITE_STRING_MODE_PV; imp_dbh->unicode = !(! SvTRUE(valuesv));
#endif #endif
return TRUE; return TRUE;
} }
if (strEQ(key, "unicode")) { if (strEQ(key, "unicode")) {
_warn_deprecated_if_possible(key, "sqlite_string_mode"); if (DBIc_has(imp_dbh, DBIcf_WARN))
warn("\"unicode\" attribute will be deprecated. Use \"sqlite_unicode\" instead.");
#if PERL_UNICODE_DOES_NOT_WORK_WELL #if PERL_UNICODE_DOES_NOT_WORK_WELL
sqlite_trace(dbh, imp_dbh, 3, form("Unicode support is disabled for this version of perl.")); sqlite_trace(dbh, imp_dbh, 3, form("Unicode support is disabled for this version of perl."));
imp_dbh->string_mode = DBD_SQLITE_STRING_MODE_PV; imp_dbh->unicode = 0;
#else #else
imp_dbh->string_mode = SvTRUE(valuesv) ? DBD_SQLITE_STRING_MODE_UNICODE_NAIVE : DBD_SQLITE_STRING_MODE_PV; imp_dbh->unicode = !(! SvTRUE(valuesv));
#endif #endif
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
} }
@ -911,18 +834,22 @@ sqlite_db_FETCH_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv)
if (strEQ(key, "sqlite_prefer_numeric_type")) { if (strEQ(key, "sqlite_prefer_numeric_type")) {
return sv_2mortal(newSViv(imp_dbh->prefer_numeric_type ? 1 : 0)); return sv_2mortal(newSViv(imp_dbh->prefer_numeric_type ? 1 : 0));
} }
if (strEQ(key, "sqlite_unicode")) {
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 #if PERL_UNICODE_DOES_NOT_WORK_WELL
sqlite_trace(dbh, imp_dbh, 3, "Unicode support is disabled for this version of perl."); sqlite_trace(dbh, imp_dbh, 3, "Unicode support is disabled for this version of perl.");
return sv_2mortal(newSViv(0)); return sv_2mortal(newSViv(0));
#else #else
return sv_2mortal(newSViv(imp_dbh->string_mode == DBD_SQLITE_STRING_MODE_UNICODE_NAIVE ? 1 : 0)); return sv_2mortal(newSViv(imp_dbh->unicode ? 1 : 0));
#endif
}
if (strEQ(key, "unicode")) {
if (DBIc_has(imp_dbh, DBIcf_WARN))
warn("\"unicode\" attribute will be deprecated. Use \"sqlite_unicode\" instead.");
#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 #endif
} }
@ -955,7 +882,7 @@ sqlite_st_prepare_sv(SV *sth, imp_sth_t *imp_sth, SV *sv_statement, SV *attribs)
stmt_list_s * new_stmt; stmt_list_s * new_stmt;
D_imp_dbh_from_sth; D_imp_dbh_from_sth;
MY_CXT.last_dbh_string_mode = imp_dbh->string_mode; MY_CXT.last_dbh_is_unicode = imp_dbh->unicode;
if (!DBIc_ACTIVE(imp_dbh)) { if (!DBIc_ACTIVE(imp_dbh)) {
sqlite_error(sth, -2, "attempt to prepare on inactive database handle"); sqlite_error(sth, -2, "attempt to prepare on inactive database handle");
@ -963,7 +890,9 @@ sqlite_st_prepare_sv(SV *sth, imp_sth_t *imp_sth, SV *sv_statement, SV *attribs)
} }
/* sqlite3_prepare wants an utf8-encoded SQL statement */ /* sqlite3_prepare wants an utf8-encoded SQL statement */
DBD_SQLITE_PREP_SV_FOR_SQLITE(sv_statement, imp_dbh->string_mode); if (imp_dbh->unicode) {
sv_utf8_upgrade(sv_statement);
}
statement = SvPV_nolen(sv_statement); statement = SvPV_nolen(sv_statement);
@ -1077,15 +1006,10 @@ sqlite_st_execute(SV *sth, imp_sth_t *imp_sth)
const char *data; const char *data;
int numtype = 0; int numtype = 0;
if (imp_dbh->string_mode & DBD_SQLITE_STRING_MODE_UNICODE_ANY) { if (imp_dbh->unicode) {
data = SvPVutf8(value, len); sv_utf8_upgrade(value);
} }
else if (imp_dbh->string_mode == DBD_SQLITE_STRING_MODE_BYTES) {
data = SvPVbyte(value, len);
}
else {
data = SvPV(value, len); data = SvPV(value, len);
}
/* /*
* XXX: For backward compatibility, it'd be better to * XXX: For backward compatibility, it'd be better to
@ -1296,9 +1220,11 @@ sqlite_st_fetch(SV *sth, imp_sth_t *imp_sth)
} }
} }
sv_setpvn(AvARRAY(av)[i], val, len); sv_setpvn(AvARRAY(av)[i], val, len);
if (imp_dbh->unicode) {
DBD_SQLITE_UTF8_DECODE_IF_NEEDED(AvARRAY(av)[i], imp_dbh->string_mode); SvUTF8_on(AvARRAY(av)[i]);
} else {
SvUTF8_off(AvARRAY(av)[i]);
}
break; break;
case SQLITE_BLOB: case SQLITE_BLOB:
sqlite_trace(sth, imp_sth, 5, form("fetch column %d as blob", i)); sqlite_trace(sth, imp_sth, 5, form("fetch column %d as blob", i));
@ -1470,9 +1396,8 @@ sqlite_st_FETCH_attrib(SV *sth, imp_sth_t *imp_sth, SV *keysv)
/* if (dot) drop table name from field name */ /* if (dot) drop table name from field name */
/* fieldname = ++dot; */ /* fieldname = ++dot; */
SV *sv_fieldname = newSVpv(fieldname, 0); SV *sv_fieldname = newSVpv(fieldname, 0);
if (imp_dbh->unicode)
DBD_SQLITE_UTF8_DECODE_IF_NEEDED(sv_fieldname, imp_dbh->string_mode); SvUTF8_on(sv_fieldname);
av_store(av, n, sv_fieldname); av_store(av, n, sv_fieldname);
} }
} }
@ -1766,7 +1691,7 @@ sqlite_db_busy_timeout(pTHX_ SV *dbh, SV *timeout )
} }
static void static void
sqlite_db_func_dispatcher(dbd_sqlite_string_mode_t string_mode, sqlite3_context *context, int argc, sqlite3_value **value) sqlite_db_func_dispatcher(int is_unicode, sqlite3_context *context, int argc, sqlite3_value **value)
{ {
dTHX; dTHX;
dSP; dSP;
@ -1781,7 +1706,7 @@ sqlite_db_func_dispatcher(dbd_sqlite_string_mode_t string_mode, sqlite3_context
PUSHMARK(SP); PUSHMARK(SP);
for ( i=0; i < argc; i++ ) { for ( i=0; i < argc; i++ ) {
XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ value[i], string_mode)); XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ value[i], is_unicode));
} }
PUTBACK; PUTBACK;
@ -1812,46 +1737,17 @@ sqlite_db_func_dispatcher(dbd_sqlite_string_mode_t string_mode, sqlite3_context
} }
static void static void
sqlite_db_func_dispatcher_unicode_naive(sqlite3_context *context, int argc, sqlite3_value **value) sqlite_db_func_dispatcher_unicode(sqlite3_context *context, int argc, sqlite3_value **value)
{ {
sqlite_db_func_dispatcher(DBD_SQLITE_STRING_MODE_UNICODE_NAIVE, context, argc, value); sqlite_db_func_dispatcher(1, context, argc, value);
} }
static void static void
sqlite_db_func_dispatcher_unicode_fallback(sqlite3_context *context, int argc, sqlite3_value **value) sqlite_db_func_dispatcher_no_unicode(sqlite3_context *context, int argc, sqlite3_value **value)
{ {
sqlite_db_func_dispatcher(DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK, context, argc, value); sqlite_db_func_dispatcher(0, 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 int
sqlite_db_create_function(pTHX_ SV *dbh, const char *name, int argc, SV *func, int flags) sqlite_db_create_function(pTHX_ SV *dbh, const char *name, int argc, SV *func, int flags)
{ {
@ -1865,20 +1761,17 @@ sqlite_db_create_function(pTHX_ SV *dbh, const char *name, int argc, SV *func, i
} }
/* Copy the function reference */ /* Copy the function reference */
if (SvOK(func)) {
func_sv = newSVsv(func); func_sv = newSVsv(func);
av_push( imp_dbh->functions, func_sv ); av_push( imp_dbh->functions, func_sv );
}
croak_if_db_is_null(); croak_if_db_is_null();
/* warn("create_function %s with %d args\n", name, argc); */ /* 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, rc = sqlite3_create_function( imp_dbh->db, name, argc, SQLITE_UTF8|flags,
func_sv, _FUNC_DISPATCHER[imp_dbh->string_mode], NULL, NULL ); func_sv,
} else { imp_dbh->unicode ? sqlite_db_func_dispatcher_unicode
rc = sqlite3_create_function( imp_dbh->db, name, argc, SQLITE_UTF8|flags, NULL, NULL, NULL, NULL ); : sqlite_db_func_dispatcher_no_unicode,
} NULL, NULL );
if ( rc != SQLITE_OK ) { if ( rc != SQLITE_OK ) {
sqlite_error(dbh, rc, form("sqlite_create_function failed with error %s", sqlite3_errmsg(imp_dbh->db))); sqlite_error(dbh, rc, form("sqlite_create_function failed with error %s", sqlite3_errmsg(imp_dbh->db)));
return FALSE; return FALSE;
@ -1934,21 +1827,6 @@ sqlite_db_load_extension(pTHX_ SV *dbh, const char *file, const char *proc)
#endif #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* HV*
sqlite_db_table_column_metadata(pTHX_ SV *dbh, SV *dbname, SV *tablename, SV *columnname) sqlite_db_table_column_metadata(pTHX_ SV *dbh, SV *dbname, SV *tablename, SV *columnname)
{ {
@ -1985,7 +1863,7 @@ sqlite_db_table_column_metadata(pTHX_ SV *dbh, SV *dbname, SV *tablename, SV *co
#endif #endif
if (rc == SQLITE_OK) { if (rc == SQLITE_OK) {
hv_stores(metadata, "data_type", datatype ? _lc(aTHX_ newSVpv(datatype, 0)) : newSV(0)); hv_stores(metadata, "data_type", datatype ? newSVpv(datatype, 0) : newSV(0));
hv_stores(metadata, "collation_name", collseq ? newSVpv(collseq, 0) : newSV(0)); hv_stores(metadata, "collation_name", collseq ? newSVpv(collseq, 0) : newSV(0));
hv_stores(metadata, "not_null", newSViv(notnull)); hv_stores(metadata, "not_null", newSViv(notnull));
hv_stores(metadata, "primary", newSViv(primary)); hv_stores(metadata, "primary", newSViv(primary));
@ -2057,7 +1935,7 @@ sqlite_db_aggr_step_dispatcher(sqlite3_context *context,
{ {
dTHX; dTHX;
dSP; dSP;
int i, string_mode = DBD_SQLITE_STRING_MODE_PV; /* TODO : find out from db handle */ int i, is_unicode = 0; /* TODO : find out from db handle */
aggrInfo *aggr; aggrInfo *aggr;
aggr = sqlite3_aggregate_context(context, sizeof (aggrInfo)); aggr = sqlite3_aggregate_context(context, sizeof (aggrInfo));
@ -2079,7 +1957,7 @@ sqlite_db_aggr_step_dispatcher(sqlite3_context *context,
PUSHMARK(SP); PUSHMARK(SP);
XPUSHs( sv_2mortal( newSVsv( aggr->aggr_inst ) )); XPUSHs( sv_2mortal( newSVsv( aggr->aggr_inst ) ));
for ( i=0; i < argc; i++ ) { for ( i=0; i < argc; i++ ) {
XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ value[i], string_mode)); XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ value[i], is_unicode));
} }
PUTBACK; PUTBACK;
@ -2195,77 +2073,70 @@ sqlite_db_create_aggregate(pTHX_ SV *dbh, const char *name, int argc, SV *aggr_p
return TRUE; 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 int
sqlite_db_collation_dispatcher(void *func, int len1, const void *string1, sqlite_db_collation_dispatcher(void *func, int len1, const void *string1,
int len2, const void *string2) int len2, const void *string2)
{ {
dTHX; dTHX;
dSP; dSP;
int cmp = 0;
int n_retval, i;
SQLITE_DB_COLLATION_BASE(func, newSVpvn( string1, len1), newSVpvn( string2, len2)); 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;
} }
int int
sqlite_db_collation_dispatcher_utf8_naive(void *func, int len1, const void *string1, sqlite_db_collation_dispatcher_utf8(void *func, int len1, const void *string1,
int len2, const void *string2) int len2, const void *string2)
{ {
dTHX; dTHX;
dSP; dSP;
int cmp = 0;
int n_retval, i;
SV *sv1, *sv2;
SQLITE_DB_COLLATION_BASE(func, newSVpvn_flags( string1, len1, SVf_UTF8), newSVpvn_flags( string2, len2, SVf_UTF8)); 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);
} }
for(i = 0; i < n_retval; i++) {
int cmp = POPi;
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);
} }
PUTBACK;
FREETMPS;
LEAVE;
typedef int (*collation_dispatch_func_t)(void *, int, const void *, int, const void *); return cmp;
}
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 int
sqlite_db_create_collation(pTHX_ SV *dbh, const char *name, SV *func) sqlite_db_create_collation(pTHX_ SV *dbh, const char *name, SV *func)
@ -2302,7 +2173,8 @@ sqlite_db_create_collation(pTHX_ SV *dbh, const char *name, SV *func)
rv = sqlite3_create_collation( rv = sqlite3_create_collation(
imp_dbh->db, name, SQLITE_UTF8, imp_dbh->db, name, SQLITE_UTF8,
func_sv, func_sv,
_COLLATION_DISPATCHER[imp_dbh->string_mode] imp_dbh->unicode ? sqlite_db_collation_dispatcher_utf8
: sqlite_db_collation_dispatcher
); );
if ( rv != SQLITE_OK ) { if ( rv != SQLITE_OK ) {

View file

@ -7,24 +7,8 @@
#define MY_CXT_KEY "DBD::SQLite::_guts" XS_VERSION #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 { typedef struct {
dbd_sqlite_string_mode_t last_dbh_string_mode; int last_dbh_is_unicode;
} my_cxt_t; } my_cxt_t;
#define PERL_UNICODE_DOES_NOT_WORK_WELL \ #define PERL_UNICODE_DOES_NOT_WORK_WELL \
@ -38,41 +22,6 @@ typedef struct {
#define sqlite3_int64 sqlite_int64 #define sqlite3_int64 sqlite_int64
#endif #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 */ /* A linked list of statements prepared by this module */
typedef struct stmt_list_s stmt_list_s; typedef struct stmt_list_s stmt_list_s;
@ -92,7 +41,7 @@ struct imp_dbh_st {
dbih_dbc_t com; dbih_dbc_t com;
/* sqlite specific bits */ /* sqlite specific bits */
sqlite3 *db; sqlite3 *db;
dbd_sqlite_string_mode_t string_mode; bool unicode;
bool handle_binary_nulls; bool handle_binary_nulls;
int timeout; int timeout;
AV *functions; AV *functions;

View file

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

View file

@ -432,7 +432,7 @@ static int perl_vt_Filter( sqlite3_vtab_cursor *pVtabCursor,
dSP; dSP;
dMY_CXT; dMY_CXT;
int i, count; int i, count;
dbd_sqlite_string_mode_t string_mode = MY_CXT.last_dbh_string_mode; int is_unicode = MY_CXT.last_dbh_is_unicode;
ENTER; ENTER;
SAVETMPS; SAVETMPS;
@ -443,7 +443,7 @@ static int perl_vt_Filter( sqlite3_vtab_cursor *pVtabCursor,
XPUSHs(sv_2mortal(newSViv(idxNum))); XPUSHs(sv_2mortal(newSViv(idxNum)));
XPUSHs(sv_2mortal(newSVpv(idxStr, 0))); XPUSHs(sv_2mortal(newSVpv(idxStr, 0)));
for(i = 0; i < argc; i++) { for(i = 0; i < argc; i++) {
XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ argv[i], string_mode)); XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ argv[i], is_unicode));
} }
PUTBACK; PUTBACK;
count = call_method("FILTER", G_VOID); count = call_method("FILTER", G_VOID);
@ -588,7 +588,7 @@ static int perl_vt_Update( sqlite3_vtab *pVTab,
dSP; dSP;
dMY_CXT; dMY_CXT;
int count, i; int count, i;
dbd_sqlite_string_mode_t string_mode = MY_CXT.last_dbh_string_mode; int is_unicode = MY_CXT.last_dbh_is_unicode;
int rc = SQLITE_ERROR; int rc = SQLITE_ERROR;
SV *rowidsv; SV *rowidsv;
@ -599,7 +599,7 @@ static int perl_vt_Update( sqlite3_vtab *pVTab,
PUSHMARK(SP); PUSHMARK(SP);
XPUSHs(((perl_vtab *) pVTab)->perl_vtab_obj); XPUSHs(((perl_vtab *) pVTab)->perl_vtab_obj);
for(i = 0; i < argc; i++) { for(i = 0; i < argc; i++) {
XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ argv[i], string_mode)); XPUSHs(stacked_sv_from_sqlite3_value(aTHX_ argv[i], is_unicode));
} }
PUTBACK; PUTBACK;
count = call_method ("_SQLITE_UPDATE", G_SCALAR); count = call_method ("_SQLITE_UPDATE", G_SCALAR);
@ -704,9 +704,8 @@ static int perl_vt_FindFunction(sqlite3_vtab *pVTab,
/* return function information for sqlite3 within *pxFunc and *ppArg */ /* return function information for sqlite3 within *pxFunc and *ppArg */
is_overloaded = coderef && SvTRUE(coderef); is_overloaded = coderef && SvTRUE(coderef);
if (is_overloaded) { if (is_overloaded) {
*pxFunc = MY_CXT.last_dbh_is_unicode ? sqlite_db_func_dispatcher_unicode
*pxFunc = _FUNC_DISPATCHER[MY_CXT.last_dbh_string_mode]; : sqlite_db_func_dispatcher_no_unicode;
*ppArg = coderef; *ppArg = coderef;
} }
@ -815,7 +814,6 @@ sqlite_db_destroy_module_data(void *pAux)
/* free module memory */ /* free module memory */
SvREFCNT_dec(init_data->dbh); SvREFCNT_dec(init_data->dbh);
sqlite3_free((char *)init_data->perl_class); sqlite3_free((char *)init_data->perl_class);
sqlite3_free(init_data);
PUTBACK; PUTBACK;
FREETMPS; FREETMPS;

View file

@ -5,7 +5,7 @@ use strict;
use DBI 1.57 (); use DBI 1.57 ();
use XSLoader (); use XSLoader ();
our $VERSION = '1.76'; our $VERSION = '1.67_03';
# sqlite_version cache (set in the XS bootstrap) # sqlite_version cache (set in the XS bootstrap)
our ($sqlite_version, $sqlite_version_number); our ($sqlite_version, $sqlite_version_number);
@ -62,7 +62,6 @@ sub driver {
DBD::SQLite::db->install_method('sqlite_db_config'); DBD::SQLite::db->install_method('sqlite_db_config');
DBD::SQLite::db->install_method('sqlite_get_autocommit'); DBD::SQLite::db->install_method('sqlite_get_autocommit');
DBD::SQLite::db->install_method('sqlite_txn_state'); DBD::SQLite::db->install_method('sqlite_txn_state');
DBD::SQLite::db->install_method('sqlite_error_offset');
$methods_are_installed++; $methods_are_installed++;
} }
@ -1074,7 +1073,7 @@ are limited by the typeless nature of the SQLite database.
=head1 SQLITE VERSION =head1 SQLITE VERSION
DBD::SQLite is usually compiled with a bundled SQLite library DBD::SQLite is usually compiled with a bundled SQLite library
(SQLite version S<3.46.1> as of this release) for consistency. (SQLite version S<3.35.3> as of this release) for consistency.
However, a different version of SQLite may sometimes be used for However, a different version of SQLite may sometimes be used for
some reasons like security, or some new experimental features. some reasons like security, or some new experimental features.
@ -1623,40 +1622,22 @@ Your sweet spot probably lies somewhere in between.
Returns the version of the SQLite library which B<DBD::SQLite> is using, Returns the version of the SQLite library which B<DBD::SQLite> is using,
e.g., "3.26.0". Can only be read. e.g., "3.26.0". Can only be read.
=item sqlite_string_mode =item sqlite_unicode
SQLite strings are simple arrays of bytes, but Perl strings can store any If set to a true value, B<DBD::SQLite> will turn the UTF-8 flag on for all
arbitrary Unicode code point. Thus, DBD::SQLite has to adopt some method text strings coming out of the database (this feature is currently disabled
of translating between those two models. This parameter defines that for perl < 5.8.5). For more details on the UTF-8 flag see
translation. L<perlunicode>. The default is for the UTF-8 flag to be turned off.
Accepted values are the following constants: Also note that due to some bizarreness in SQLite's type system (see
=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 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 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 >> (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 explicitly using the 3-argument form of L<DBI/bind_param> when doing
updates: updates:
use DBI qw(:sql_types); use DBI qw(:sql_types);
use DBD::SQLite::Constants ':dbd_sqlite_string_mode'; $dbh->{sqlite_unicode} = 1;
$dbh->{sqlite_string_mode} = DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK;
my $sth = $dbh->prepare("INSERT INTO mytable (blobcolumn) VALUES (?)"); my $sth = $dbh->prepare("INSERT INTO mytable (blobcolumn) VALUES (?)");
# Binary_data will be stored as is. # Binary_data will be stored as is.
@ -1664,31 +1645,9 @@ updates:
Defining the column type as C<BLOB> in the DDL is B<not> sufficient. Defining the column type as C<BLOB> in the DDL is B<not> sufficient.
=item * DBD_SQLITE_STRING_MODE_UNICODE_STRICT: Like This attribute was originally named as C<unicode>, and renamed to
DBD_SQLITE_STRING_MODE_UNICODE_FALLBACK but usually throws an exception C<sqlite_unicode> for integrity since version 1.26_06. Old C<unicode>
rather than a warning if SQLite sends invalid UTF-8. (In Perl callbacks attribute is still accessible but will be deprecated in the near future.
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 =item sqlite_allow_multiple_statements
@ -1749,8 +1708,7 @@ 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 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> ESCAPE character by including an 'Escape' attribute in \%attr. The C<$type>
argument accepts a comma separated list of the following types 'TABLE', argument accepts a comma separated list of the following types 'TABLE',
'INDEX', 'VIEW', 'TRIGGER', 'LOCAL TEMPORARY' and 'SYSTEM TABLE' 'VIEW', 'LOCAL TEMPORARY' and 'SYSTEM TABLE' (by default all are returned).
(by default all are returned).
Note that a statement handle is returned, and not a direct list of tables. Note that a statement handle is returned, and not a direct list of tables.
The following fields are returned: The following fields are returned:
@ -1763,8 +1721,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_NAME>: The name of the table or view.
B<TABLE_TYPE>: The type of object returned. Will be one of 'TABLE', 'INDEX', B<TABLE_TYPE>: The type of object returned. Will be one of 'TABLE', 'VIEW',
'VIEW', 'TRIGGER', 'LOCAL TEMPORARY' or 'SYSTEM TABLE'. 'LOCAL TEMPORARY' or 'SYSTEM TABLE'.
=head2 primary_key, primary_key_info =head2 primary_key, primary_key_info
@ -2299,20 +2257,12 @@ Calling this method with a true value enables loading (external)
SQLite3 extensions. After the call, you can load extensions like this: SQLite3 extensions. After the call, you can load extensions like this:
$dbh->sqlite_enable_load_extension(1); $dbh->sqlite_enable_load_extension(1);
$sth = $dbh->prepare("select load_extension('libmemvfs.so')") $sth = $dbh->prepare("select load_extension('libsqlitefunctions.so')")
or die "Cannot prepare: " . $dbh->errstr(); or die "Cannot prepare: " . $dbh->errstr();
=head2 $dbh->sqlite_load_extension( $file, $proc ) =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 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>: 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>.
$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 ) =head2 $dbh->sqlite_trace( $code_ref )
@ -2433,12 +2383,6 @@ can be imported from DBD::SQLite::Constants. You may pass an optional
schema name (usually "main"). If SQLite does not support this function, schema name (usually "main"). If SQLite does not support this function,
or if you pass a wrong schema name, -1 is returned. 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 =head1 DRIVER FUNCTIONS
=head2 DBD::SQLite::compile_options() =head2 DBD::SQLite::compile_options()
@ -2601,17 +2545,18 @@ or
=head2 Unicode handling =head2 Unicode handling
Depending on the C<< $dbh->{sqlite_string_mode} >> value, strings coming If the attribute C<< $dbh->{sqlite_unicode} >> is set, strings coming from
from the database and passed to the collation function may be decoded as the database and passed to the collation function will be properly
UTF-8. This only works, though, if the C<sqlite_string_mode> attribute is tagged with the utf8 flag; but this only works if the
set B<before> the first call to a perl collation sequence. The recommended C<sqlite_unicode> attribute is set B<before> the first call to
way to activate unicode is to set C<sqlite_string_mode> at connection time: a perl collation sequence . The recommended way to activate unicode
is to set the parameter at connection time :
my $dbh = DBI->connect( my $dbh = DBI->connect(
"dbi:SQLite:dbname=foo", "", "", "dbi:SQLite:dbname=foo", "", "",
{ {
RaiseError => 1, RaiseError => 1,
sqlite_string_mode => DBD_SQLITE_STRING_MODE_UNICODE_STRICT, sqlite_unicode => 1,
} }
); );
@ -2633,7 +2578,7 @@ characters :
use DBD::SQLite; use DBD::SQLite;
$DBD::SQLite::COLLATION{no_accents} = sub { $DBD::SQLite::COLLATION{no_accents} = sub {
my ( $a, $b ) = map lc, @_; my ( $a, $b ) = map lc, @_;
tr[àâáäåãçðèêéëìîíïñòôóöõøùûúüý] tr[àâáäåãçðèêéëìîíïñòôóöõøùûúüý]
[aaaaaacdeeeeiiiinoooooouuuuy] for $a, $b; [aaaaaacdeeeeiiiinoooooouuuuy] for $a, $b;
$a cmp $b; $a cmp $b;
}; };

View file

@ -8,11 +8,6 @@ use warnings;
use base 'Exporter'; use base 'Exporter';
use DBD::SQLite; use DBD::SQLite;
our @EXPORT_OK = ( 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 # allowed_return_values_from_sqlite3_txn_state
qw/ qw/
SQLITE_TXN_NONE SQLITE_TXN_NONE
@ -87,8 +82,6 @@ our @EXPORT_OK = (
SQLITE_DBCONFIG_MAX SQLITE_DBCONFIG_MAX
SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
SQLITE_DBCONFIG_RESET_DATABASE SQLITE_DBCONFIG_RESET_DATABASE
SQLITE_DBCONFIG_REVERSE_SCANORDER
SQLITE_DBCONFIG_STMT_SCANSTATUS
SQLITE_DBCONFIG_TRIGGER_EQP SQLITE_DBCONFIG_TRIGGER_EQP
SQLITE_DBCONFIG_TRUSTED_SCHEMA SQLITE_DBCONFIG_TRUSTED_SCHEMA
SQLITE_DBCONFIG_WRITABLE_SCHEMA SQLITE_DBCONFIG_WRITABLE_SCHEMA
@ -109,7 +102,6 @@ our @EXPORT_OK = (
SQLITE_CANTOPEN_SYMLINK SQLITE_CANTOPEN_SYMLINK
SQLITE_CONSTRAINT_CHECK SQLITE_CONSTRAINT_CHECK
SQLITE_CONSTRAINT_COMMITHOOK SQLITE_CONSTRAINT_COMMITHOOK
SQLITE_CONSTRAINT_DATATYPE
SQLITE_CONSTRAINT_FOREIGNKEY SQLITE_CONSTRAINT_FOREIGNKEY
SQLITE_CONSTRAINT_FUNCTION SQLITE_CONSTRAINT_FUNCTION
SQLITE_CONSTRAINT_NOTNULL SQLITE_CONSTRAINT_NOTNULL
@ -142,7 +134,6 @@ our @EXPORT_OK = (
SQLITE_IOERR_FSTAT SQLITE_IOERR_FSTAT
SQLITE_IOERR_FSYNC SQLITE_IOERR_FSYNC
SQLITE_IOERR_GETTEMPPATH SQLITE_IOERR_GETTEMPPATH
SQLITE_IOERR_IN_PAGE
SQLITE_IOERR_LOCK SQLITE_IOERR_LOCK
SQLITE_IOERR_MMAP SQLITE_IOERR_MMAP
SQLITE_IOERR_NOMEM SQLITE_IOERR_NOMEM
@ -161,7 +152,6 @@ our @EXPORT_OK = (
SQLITE_IOERR_WRITE SQLITE_IOERR_WRITE
SQLITE_LOCKED_SHAREDCACHE SQLITE_LOCKED_SHAREDCACHE
SQLITE_LOCKED_VTAB SQLITE_LOCKED_VTAB
SQLITE_NOTICE_RBU
SQLITE_NOTICE_RECOVER_ROLLBACK SQLITE_NOTICE_RECOVER_ROLLBACK
SQLITE_NOTICE_RECOVER_WAL SQLITE_NOTICE_RECOVER_WAL
SQLITE_OK_SYMLINK SQLITE_OK_SYMLINK
@ -177,7 +167,6 @@ our @EXPORT_OK = (
# flags_for_file_open_operations # flags_for_file_open_operations
qw/ qw/
SQLITE_OPEN_CREATE SQLITE_OPEN_CREATE
SQLITE_OPEN_EXRESCODE
SQLITE_OPEN_FULLMUTEX SQLITE_OPEN_FULLMUTEX
SQLITE_OPEN_MEMORY SQLITE_OPEN_MEMORY
SQLITE_OPEN_NOFOLLOW SQLITE_OPEN_NOFOLLOW
@ -195,7 +184,6 @@ our @EXPORT_OK = (
SQLITE_DETERMINISTIC SQLITE_DETERMINISTIC
SQLITE_DIRECTONLY SQLITE_DIRECTONLY
SQLITE_INNOCUOUS SQLITE_INNOCUOUS
SQLITE_RESULT_SUBTYPE
SQLITE_SUBTYPE SQLITE_SUBTYPE
/, /,
@ -205,7 +193,6 @@ our @EXPORT_OK = (
SQLITE_FLOAT SQLITE_FLOAT
SQLITE_INTEGER SQLITE_INTEGER
SQLITE_NULL SQLITE_NULL
SQLITE_TEXT
/, /,
# result_codes # result_codes
@ -285,7 +272,6 @@ our %EXPORT_TAGS = (
SQLITE_CONSTRAINT SQLITE_CONSTRAINT
SQLITE_CONSTRAINT_CHECK SQLITE_CONSTRAINT_CHECK
SQLITE_CONSTRAINT_COMMITHOOK SQLITE_CONSTRAINT_COMMITHOOK
SQLITE_CONSTRAINT_DATATYPE
SQLITE_CONSTRAINT_FOREIGNKEY SQLITE_CONSTRAINT_FOREIGNKEY
SQLITE_CONSTRAINT_FUNCTION SQLITE_CONSTRAINT_FUNCTION
SQLITE_CONSTRAINT_NOTNULL SQLITE_CONSTRAINT_NOTNULL
@ -325,16 +311,9 @@ our %EXPORT_TAGS = (
SQLITE_DBCONFIG_MAX SQLITE_DBCONFIG_MAX
SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
SQLITE_DBCONFIG_RESET_DATABASE SQLITE_DBCONFIG_RESET_DATABASE
SQLITE_DBCONFIG_REVERSE_SCANORDER
SQLITE_DBCONFIG_STMT_SCANSTATUS
SQLITE_DBCONFIG_TRIGGER_EQP SQLITE_DBCONFIG_TRIGGER_EQP
SQLITE_DBCONFIG_TRUSTED_SCHEMA SQLITE_DBCONFIG_TRUSTED_SCHEMA
SQLITE_DBCONFIG_WRITABLE_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_DELETE
SQLITE_DENY SQLITE_DENY
SQLITE_DETACH SQLITE_DETACH
@ -383,7 +362,6 @@ our %EXPORT_TAGS = (
SQLITE_IOERR_FSTAT SQLITE_IOERR_FSTAT
SQLITE_IOERR_FSYNC SQLITE_IOERR_FSYNC
SQLITE_IOERR_GETTEMPPATH SQLITE_IOERR_GETTEMPPATH
SQLITE_IOERR_IN_PAGE
SQLITE_IOERR_LOCK SQLITE_IOERR_LOCK
SQLITE_IOERR_MMAP SQLITE_IOERR_MMAP
SQLITE_IOERR_NOMEM SQLITE_IOERR_NOMEM
@ -422,14 +400,12 @@ our %EXPORT_TAGS = (
SQLITE_NOTADB SQLITE_NOTADB
SQLITE_NOTFOUND SQLITE_NOTFOUND
SQLITE_NOTICE SQLITE_NOTICE
SQLITE_NOTICE_RBU
SQLITE_NOTICE_RECOVER_ROLLBACK SQLITE_NOTICE_RECOVER_ROLLBACK
SQLITE_NOTICE_RECOVER_WAL SQLITE_NOTICE_RECOVER_WAL
SQLITE_NULL SQLITE_NULL
SQLITE_OK SQLITE_OK
SQLITE_OK_SYMLINK SQLITE_OK_SYMLINK
SQLITE_OPEN_CREATE SQLITE_OPEN_CREATE
SQLITE_OPEN_EXRESCODE
SQLITE_OPEN_FULLMUTEX SQLITE_OPEN_FULLMUTEX
SQLITE_OPEN_MEMORY SQLITE_OPEN_MEMORY
SQLITE_OPEN_NOFOLLOW SQLITE_OPEN_NOFOLLOW
@ -454,13 +430,11 @@ our %EXPORT_TAGS = (
SQLITE_READONLY_ROLLBACK SQLITE_READONLY_ROLLBACK
SQLITE_RECURSIVE SQLITE_RECURSIVE
SQLITE_REINDEX SQLITE_REINDEX
SQLITE_RESULT_SUBTYPE
SQLITE_ROW SQLITE_ROW
SQLITE_SAVEPOINT SQLITE_SAVEPOINT
SQLITE_SCHEMA SQLITE_SCHEMA
SQLITE_SELECT SQLITE_SELECT
SQLITE_SUBTYPE SQLITE_SUBTYPE
SQLITE_TEXT
SQLITE_TOOBIG SQLITE_TOOBIG
SQLITE_TRANSACTION SQLITE_TRANSACTION
SQLITE_TXN_NONE SQLITE_TXN_NONE
@ -541,21 +515,11 @@ our %EXPORT_TAGS = (
SQLITE_DBCONFIG_MAX SQLITE_DBCONFIG_MAX
SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE
SQLITE_DBCONFIG_RESET_DATABASE SQLITE_DBCONFIG_RESET_DATABASE
SQLITE_DBCONFIG_REVERSE_SCANORDER
SQLITE_DBCONFIG_STMT_SCANSTATUS
SQLITE_DBCONFIG_TRIGGER_EQP SQLITE_DBCONFIG_TRIGGER_EQP
SQLITE_DBCONFIG_TRUSTED_SCHEMA SQLITE_DBCONFIG_TRUSTED_SCHEMA
SQLITE_DBCONFIG_WRITABLE_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/ extended_result_codes => [qw/
SQLITE_ABORT_ROLLBACK SQLITE_ABORT_ROLLBACK
SQLITE_AUTH_USER SQLITE_AUTH_USER
@ -570,7 +534,6 @@ our %EXPORT_TAGS = (
SQLITE_CANTOPEN_SYMLINK SQLITE_CANTOPEN_SYMLINK
SQLITE_CONSTRAINT_CHECK SQLITE_CONSTRAINT_CHECK
SQLITE_CONSTRAINT_COMMITHOOK SQLITE_CONSTRAINT_COMMITHOOK
SQLITE_CONSTRAINT_DATATYPE
SQLITE_CONSTRAINT_FOREIGNKEY SQLITE_CONSTRAINT_FOREIGNKEY
SQLITE_CONSTRAINT_FUNCTION SQLITE_CONSTRAINT_FUNCTION
SQLITE_CONSTRAINT_NOTNULL SQLITE_CONSTRAINT_NOTNULL
@ -603,7 +566,6 @@ our %EXPORT_TAGS = (
SQLITE_IOERR_FSTAT SQLITE_IOERR_FSTAT
SQLITE_IOERR_FSYNC SQLITE_IOERR_FSYNC
SQLITE_IOERR_GETTEMPPATH SQLITE_IOERR_GETTEMPPATH
SQLITE_IOERR_IN_PAGE
SQLITE_IOERR_LOCK SQLITE_IOERR_LOCK
SQLITE_IOERR_MMAP SQLITE_IOERR_MMAP
SQLITE_IOERR_NOMEM SQLITE_IOERR_NOMEM
@ -622,7 +584,6 @@ our %EXPORT_TAGS = (
SQLITE_IOERR_WRITE SQLITE_IOERR_WRITE
SQLITE_LOCKED_SHAREDCACHE SQLITE_LOCKED_SHAREDCACHE
SQLITE_LOCKED_VTAB SQLITE_LOCKED_VTAB
SQLITE_NOTICE_RBU
SQLITE_NOTICE_RECOVER_ROLLBACK SQLITE_NOTICE_RECOVER_ROLLBACK
SQLITE_NOTICE_RECOVER_WAL SQLITE_NOTICE_RECOVER_WAL
SQLITE_OK_SYMLINK SQLITE_OK_SYMLINK
@ -637,7 +598,6 @@ our %EXPORT_TAGS = (
flags_for_file_open_operations => [qw/ flags_for_file_open_operations => [qw/
SQLITE_OPEN_CREATE SQLITE_OPEN_CREATE
SQLITE_OPEN_EXRESCODE
SQLITE_OPEN_FULLMUTEX SQLITE_OPEN_FULLMUTEX
SQLITE_OPEN_MEMORY SQLITE_OPEN_MEMORY
SQLITE_OPEN_NOFOLLOW SQLITE_OPEN_NOFOLLOW
@ -654,7 +614,6 @@ our %EXPORT_TAGS = (
SQLITE_DETERMINISTIC SQLITE_DETERMINISTIC
SQLITE_DIRECTONLY SQLITE_DIRECTONLY
SQLITE_INNOCUOUS SQLITE_INNOCUOUS
SQLITE_RESULT_SUBTYPE
SQLITE_SUBTYPE SQLITE_SUBTYPE
/], /],
@ -663,7 +622,6 @@ our %EXPORT_TAGS = (
SQLITE_FLOAT SQLITE_FLOAT
SQLITE_INTEGER SQLITE_INTEGER
SQLITE_NULL SQLITE_NULL
SQLITE_TEXT
/], /],
result_codes => [qw/ result_codes => [qw/
@ -736,7 +694,7 @@ DBD::SQLite::Constants - common SQLite constants
=head1 DESCRIPTION =head1 DESCRIPTION
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. 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<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. This module does not export anything by default.
@ -888,26 +846,6 @@ This module does not export anything by default.
=item SQLITE_DBCONFIG_TRUSTED_SCHEMA =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 =back
=head2 extended_result_codes =head2 extended_result_codes
@ -1060,12 +998,6 @@ This module does not export anything by default.
=item SQLITE_IOERR_CORRUPTFS =item SQLITE_IOERR_CORRUPTFS
=item SQLITE_CONSTRAINT_DATATYPE
=item SQLITE_NOTICE_RBU
=item SQLITE_IOERR_IN_PAGE
=back =back
=head2 file_open (flags_for_file_open_operations) =head2 file_open (flags_for_file_open_operations)
@ -1094,8 +1026,6 @@ This module does not export anything by default.
=item SQLITE_OPEN_SUPER_JOURNAL =item SQLITE_OPEN_SUPER_JOURNAL
=item SQLITE_OPEN_EXRESCODE
=back =back
=head2 function_flags =head2 function_flags
@ -1110,8 +1040,6 @@ This module does not export anything by default.
=item SQLITE_INNOCUOUS =item SQLITE_INNOCUOUS
=item SQLITE_RESULT_SUBTYPE
=back =back
=head2 datatypes (fundamental_datatypes) =head2 datatypes (fundamental_datatypes)
@ -1126,8 +1054,6 @@ This module does not export anything by default.
=item SQLITE_NULL =item SQLITE_NULL
=item SQLITE_TEXT
=back =back
=head2 result_codes =head2 result_codes

View file

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

58349
sqlite3.c

File diff suppressed because it is too large Load diff

1597
sqlite3.h

File diff suppressed because it is too large Load diff

View file

@ -331,41 +331,12 @@ struct sqlite3_api_routines {
const char *(*filename_journal)(const char*); const char *(*filename_journal)(const char*);
const char *(*filename_wal)(const char*); const char *(*filename_wal)(const char*);
/* Version 3.32.0 and later */ /* Version 3.32.0 and later */
const char *(*create_filename)(const char*,const char*,const char*, char *(*create_filename)(const char*,const char*,const char*,
int,const char**); int,const char**);
void (*free_filename)(const char*); void (*free_filename)(char*);
sqlite3_file *(*database_file_object)(const char*); sqlite3_file *(*database_file_object)(const char*);
/* Version 3.34.0 and later */ /* Version 3.34.0 and later */
int (*txn_state)(sqlite3*,const char*); 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*));
}; };
/* /*
@ -672,33 +643,6 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_database_file_object sqlite3_api->database_file_object #define sqlite3_database_file_object sqlite3_api->database_file_object
/* Version 3.34.0 and later */ /* Version 3.34.0 and later */
#define sqlite3_txn_state sqlite3_api->txn_state #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) */ #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)

View file

@ -7,10 +7,6 @@ use SQLiteTest qw/connect_ok @CALL_FUNCS/;
use Test::More; use Test::More;
use if -d ".git", "Test::FailWarnings"; use if -d ".git", "Test::FailWarnings";
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
my $unicode_opt = DBD_SQLITE_STRING_MODE_UNICODE_STRICT;
my $show_diag = 0; my $show_diag = 0;
foreach my $call_func (@CALL_FUNCS) { foreach my $call_func (@CALL_FUNCS) {
@ -34,9 +30,9 @@ foreach my $call_func (@CALL_FUNCS) {
skip( 'Unicode is not supported before 5.8.5', 2 ); skip( 'Unicode is not supported before 5.8.5', 2 );
} }
my $file = 'foo'.$$; my $file = 'foo'.$$;
my $dbh = DBI->connect( "dbi:SQLite:dbname=$file;sqlite_string_mode=$unicode_opt", '', '' ); my $dbh = DBI->connect( "dbi:SQLite:dbname=$file;sqlite_unicode=1", '', '' );
isa_ok( $dbh, 'DBI::db' ); isa_ok( $dbh, 'DBI::db' );
is( $dbh->{sqlite_string_mode}, $unicode_opt, 'Unicode is on' ); is( $dbh->{sqlite_unicode}, 1, 'Unicode is on' );
$dbh->disconnect; $dbh->disconnect;
unlink $file; unlink $file;
} }

View file

@ -25,12 +25,4 @@ ok($@, 'Statement 2 generated an error');
is( $DBI::err, 19, '$DBI::err ok' ); is( $DBI::err, 19, '$DBI::err ok' );
like( $DBI::errstr, qr/column a is not unique|UNIQUE constraint failed/, '$DBI::errstr 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; done_testing;

View file

@ -150,10 +150,6 @@ foreach my $call_func (@CALL_FUNCS) { for my $flags (@function_flags) {
$result = $dbh->selectrow_arrayref( "SELECT typeof(md5_blob('my_blob'))" ); $result = $dbh->selectrow_arrayref( "SELECT typeof(md5_blob('my_blob'))" );
is_deeply( $result, [ 'blob' ], "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; $dbh->disconnect;
}} }}

View file

@ -8,10 +8,6 @@ use SQLiteTest;
use Test::More; use Test::More;
use if -d ".git", "Test::FailWarnings"; 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() } BEGIN { requires_unicode_support() }
# #
@ -55,7 +51,7 @@ ok(
my ($textback, $bytesback); my ($textback, $bytesback);
SCOPE: { SCOPE: {
my $dbh = connect_ok( dbfile => 'foo', RaiseError => 1 ); my $dbh = connect_ok( dbfile => 'foo', RaiseError => 1 );
is( $dbh->{sqlite_string_mode}, DBD::SQLite::Constants::DBD_SQLITE_STRING_MODE_PV, 'default string mode is pv' ); is( $dbh->{sqlite_unicode}, 0, 'Unicode is off' );
ok( ok(
$dbh->do("CREATE TABLE table1 (a TEXT, b BLOB)"), $dbh->do("CREATE TABLE table1 (a TEXT, b BLOB)"),
'CREATE TABLE', 'CREATE TABLE',
@ -77,8 +73,8 @@ SCOPE: {
# Start over but now activate Unicode support. # Start over but now activate Unicode support.
SCOPE: { SCOPE: {
my $dbh = connect_ok( dbfile => 'foo', sqlite_string_mode => $unicode_opt ); my $dbh = connect_ok( dbfile => 'foo', sqlite_unicode => 1 );
is( $dbh->{sqlite_string_mode}, $unicode_opt, 'Unicode is on' ); is( $dbh->{sqlite_unicode}, 1, 'Unicode is on' );
($textback, $bytesback) = database_roundtrip($dbh, $utfstring, $bytestring); ($textback, $bytesback) = database_roundtrip($dbh, $utfstring, $bytestring);

View file

@ -7,9 +7,6 @@ use Test::More;
use if -d ".git", "Test::FailWarnings"; use if -d ".git", "Test::FailWarnings";
use Encode qw/decode/; use Encode qw/decode/;
use DBD::SQLite; 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 { requires_unicode_support(); }
@ -74,10 +71,10 @@ is($DBD::SQLite::COLLATION{foo}, \&by_num_desc, "overridden collation");
foreach my $call_func (@CALL_FUNCS) { foreach my $call_func (@CALL_FUNCS) {
for my $unicode_opt (DBD_SQLITE_STRING_MODE_BYTES, DBD_SQLITE_STRING_MODE_UNICODE_STRICT) { for my $use_unicode (0, 1) {
# connect # connect
my $dbh = connect_ok( RaiseError => 1, sqlite_string_mode => $unicode_opt ); my $dbh = connect_ok( RaiseError => 1, sqlite_unicode => $use_unicode );
# populate test data # populate test data
my @words = qw{ my @words = qw{
@ -87,7 +84,7 @@ foreach my $call_func (@CALL_FUNCS) {
HAT hâôer HAT hâôer
féôu fêôe fèöe ferme féôu fêôe fèöe ferme
}; };
if ($unicode_opt != DBD_SQLITE_STRING_MODE_BYTES) { if ($use_unicode) {
utf8::upgrade($_) foreach @words; utf8::upgrade($_) foreach @words;
} }

View file

@ -10,10 +10,6 @@ use if -d ".git", "Test::FailWarnings";
use File::Temp (); use File::Temp ();
use File::Spec::Functions ':ALL'; 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() } BEGIN { requires_unicode_support() }
my $dir = File::Temp::tempdir( CLEANUP => 1 ); my $dir = File::Temp::tempdir( CLEANUP => 1 );
@ -59,7 +55,7 @@ foreach my $subdir ( 'longascii', 'adatb
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile", undef, undef, { my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile", undef, undef, {
RaiseError => 1, RaiseError => 1,
PrintError => 0, PrintError => 0,
sqlite_string_mode => $unicode_opt, sqlite_unicode => 1,
} ); } );
isa_ok( $dbh, 'DBI::db' ); isa_ok( $dbh, 'DBI::db' );
}; };
@ -71,7 +67,7 @@ foreach my $subdir ( 'longascii', 'adatb
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile", undef, undef, { my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile", undef, undef, {
RaiseError => 1, RaiseError => 1,
PrintError => 0, PrintError => 0,
sqlite_string_mode => $unicode_opt, sqlite_unicode => 1,
} ); } );
isa_ok( $dbh, 'DBI::db' ); isa_ok( $dbh, 'DBI::db' );
}; };

View file

@ -28,14 +28,13 @@ BEGIN {
use locale; use locale;
use DBD::SQLite; use DBD::SQLite;
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
foreach my $call_func (@CALL_FUNCS) { foreach my $call_func (@CALL_FUNCS) {
for my $string_mode (DBD_SQLITE_STRING_MODE_BYTES, DBD_SQLITE_STRING_MODE_UNICODE_STRICT) { for my $use_unicode (0, 1) {
# connect # connect
my $dbh = connect_ok( RaiseError => 1, sqlite_string_mode => $string_mode ); my $dbh = connect_ok( RaiseError => 1, sqlite_unicode => $use_unicode );
# The following tests are about ordering, so don't reverse! # The following tests are about ordering, so don't reverse!
if ($dbh->selectrow_array('PRAGMA reverse_unordered_selects')) { if ($dbh->selectrow_array('PRAGMA reverse_unordered_selects')) {
@ -44,7 +43,7 @@ foreach my $call_func (@CALL_FUNCS) {
# populate test data # populate test data
my @vals = @words; my @vals = @words;
if ($string_mode == DBD_SQLITE_STRING_MODE_BYTES) { if ($use_unicode) {
utf8::upgrade($_) foreach @vals; utf8::upgrade($_) foreach @vals;
} }

View file

@ -1,15 +1,11 @@
use strict; use strict;
use warnings; use warnings;
no if $] >= 5.022, "warnings", "locale";
use lib "t/lib"; use lib "t/lib";
use Time::HiRes qw/time/;
use SQLiteTest; use SQLiteTest;
use Test::More; use Test::More;
use if -d ".git", "Test::FailWarnings"; use if -d ".git", "Test::FailWarnings";
use DBD::SQLite; use DBD::SQLite;
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
# Avoid slowdown with -DDEBUGGING:
${^UTF8CACHE} = 1;
my @texts = ("il était une bergère", my @texts = ("il était une bergère",
"qui gardait ses moutons", "qui gardait ses moutons",
@ -28,9 +24,6 @@ my @tests = (
["(il OR elle) AND un*" => 0, 2 ], ["(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 { BEGIN {
requires_unicode_support(); requires_unicode_support();
@ -42,19 +35,31 @@ BEGIN {
} }
} }
# Perl may spit a warning on locale
# use Test::NoWarnings;
sub Unicode_Word_tokenizer { # see also: Search::Tokenizer 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
return sub { return sub {
my $string = shift; my $string = shift;
my $regex = qr/\p{Word}+/; my $regex = qr/\w+/;
my $term_index = 0; my $term_index = 0;
return sub { return sub {
$string =~ /$regex/g or return; # either match, or no more token $string =~ /$regex/g or return; # either match, or no more token
my $term = $&; my ($start, $end) = ($-[0], $+[0]);
my $end = pos $string; # $+[0] is much slower my $term = substr($string, $start, my $len = $end-$start);
my $len = length($term);
my $start = $end - $len;
return ($term, $len, $start, $end, $term_index++); return ($term, $len, $start, $end, $term_index++);
}; };
}; };
@ -62,10 +67,10 @@ sub Unicode_Word_tokenizer { # see also: Search::Tokenizer
use DBD::SQLite; use DBD::SQLite;
for my $string_mode (DBD_SQLITE_STRING_MODE_BYTES, DBD_SQLITE_STRING_MODE_UNICODE_STRICT) { for my $use_unicode (0, 1) {
# connect # connect
my $dbh = connect_ok( RaiseError => 1, sqlite_string_mode => $string_mode ); my $dbh = connect_ok( RaiseError => 1, sqlite_unicode => $use_unicode );
for my $fts (qw/fts3 fts4/) { for my $fts (qw/fts3 fts4/) {
next if $fts eq 'fts4' && !has_sqlite('3.7.4'); next if $fts eq 'fts4' && !has_sqlite('3.7.4');
@ -73,7 +78,7 @@ for my $string_mode (DBD_SQLITE_STRING_MODE_BYTES, DBD_SQLITE_STRING_MODE_UNICOD
# create fts table # create fts table
$dbh->do(<<"") or die DBI::errstr; $dbh->do(<<"") or die DBI::errstr;
CREATE VIRTUAL TABLE try_$fts CREATE VIRTUAL TABLE try_$fts
USING $fts(content, tokenize=perl 'main::Unicode_Word_tokenizer') USING $fts(content, tokenize=perl 'main::locale_tokenizer')
# populate it # populate it
my $insert_sth = $dbh->prepare(<<"") or die DBI::errstr; my $insert_sth = $dbh->prepare(<<"") or die DBI::errstr;
@ -97,43 +102,9 @@ for my $string_mode (DBD_SQLITE_STRING_MODE_BYTES, DBD_SQLITE_STRING_MODE_UNICOD
my ($query, @expected) = @$t; my ($query, @expected) = @$t;
@expected = map {$doc_ids[$_]} @expected; @expected = map {$doc_ids[$_]} @expected;
my $results = $dbh->selectcol_arrayref($sql, undef, $query); my $results = $dbh->selectcol_arrayref($sql, undef, $query);
is_deeply($results, \@expected, "$query ($fts, string_mode=$string_mode)"); is_deeply($results, \@expected, "$query ($fts, unicode=$use_unicode)");
} }
} }
# 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"');
} }
} }

View file

@ -7,8 +7,6 @@ use Test::More;
BEGIN { requires_unicode_support() } BEGIN { requires_unicode_support() }
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
# special case for multibyte (non-ASCII) character class, # special case for multibyte (non-ASCII) character class,
# which only works correctly under the unicode mode # which only works correctly under the unicode mode
my @words = ("\x{e3}\x{83}\x{86}\x{e3}\x{82}\x{b9}\x{e3}\x{83}\x{88}", "\x{e3}\x{83}\x{86}\x{e3}\x{83}\x{b3}\x{e3}\x{83}\x{88}"); # テスト テント my @words = ("\x{e3}\x{83}\x{86}\x{e3}\x{82}\x{b9}\x{e3}\x{83}\x{88}", "\x{e3}\x{83}\x{86}\x{e3}\x{83}\x{b3}\x{e3}\x{83}\x{88}"); # テスト テント
@ -17,15 +15,15 @@ my $regex = "\x{e3}\x{83}\x{86}[\x{e3}\x{82}\x{b9}\x{e3}\x{83}\x{b3}]\x{e3}\x{83
foreach my $call_func (@CALL_FUNCS) { foreach my $call_func (@CALL_FUNCS) {
for my $string_mode (DBD_SQLITE_STRING_MODE_PV, DBD_SQLITE_STRING_MODE_UNICODE_STRICT) { for my $use_unicode (0, 1) {
# connect # connect
my $dbh = connect_ok( RaiseError => 1, sqlite_string_mode => $string_mode ); my $dbh = connect_ok( RaiseError => 1, sqlite_unicode => $use_unicode );
# populate test data # populate test data
my @vals = @words; my @vals = @words;
my $re = $regex; my $re = $regex;
if ($string_mode == DBD_SQLITE_STRING_MODE_UNICODE_STRICT) { if ($use_unicode) {
utf8::decode($_) foreach @vals; utf8::decode($_) foreach @vals;
utf8::decode($re); utf8::decode($re);
} }

View file

@ -1,63 +0,0 @@
# 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

@ -5,14 +5,10 @@ use SQLiteTest;
use Test::More; use Test::More;
use if -d ".git", "Test::FailWarnings"; 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(); } BEGIN { requires_unicode_support(); }
my $dbh = connect_ok( sqlite_string_mode => $unicode_opt ); my $dbh = connect_ok( sqlite_unicode => 1 );
is( $dbh->{sqlite_string_mode}, $unicode_opt, 'string mode is unicode/strict' ); is( $dbh->{sqlite_unicode}, 1, 'Unicode is on' );
ok( $dbh->do(<<'END_SQL'), 'CREATE TABLE' ); ok( $dbh->do(<<'END_SQL'), 'CREATE TABLE' );
CREATE TABLE foo ( CREATE TABLE foo (

View file

@ -5,14 +5,10 @@ use SQLiteTest;
use Test::More; use Test::More;
use if -d ".git", "Test::FailWarnings"; 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() } BEGIN { requires_unicode_support() }
foreach my $call_func (@CALL_FUNCS) { foreach my $call_func (@CALL_FUNCS) {
my $dbh = connect_ok( sqlite_string_mode => $unicode_opt ); my $dbh = connect_ok( sqlite_unicode => 1 );
ok($dbh->$call_func( "perl_uc", 1, \&perl_uc, "create_function" )); ok($dbh->$call_func( "perl_uc", 1, \&perl_uc, "create_function" ));
ok( $dbh->do(<<'END_SQL'), 'CREATE TABLE' ); ok( $dbh->do(<<'END_SQL'), 'CREATE TABLE' );

View file

@ -6,11 +6,9 @@ use Test::More;
use if -d ".git", "Test::FailWarnings"; use if -d ".git", "Test::FailWarnings";
use DBI qw/:sql_types/; use DBI qw/:sql_types/;
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
BEGIN{ requires_unicode_support(); } BEGIN{ requires_unicode_support(); }
my $dbh = connect_ok(sqlite_string_mode => DBD_SQLITE_STRING_MODE_UNICODE_STRICT); my $dbh = connect_ok(sqlite_unicode => 1);
$dbh->do('create table test1 (id integer, b blob)'); $dbh->do('create table test1 (id integer, b blob)');
my $blob = "\x{82}\x{A0}"; my $blob = "\x{82}\x{A0}";

View file

@ -6,8 +6,6 @@ use Test::More;
use if -d ".git", "Test::FailWarnings"; use if -d ".git", "Test::FailWarnings";
use Encode; use Encode;
use DBD::SQLite::Constants ':dbd_sqlite_string_mode';
BEGIN { requires_unicode_support() } BEGIN { requires_unicode_support() }
unicode_test("\x{263A}"); # (decoded) smiley character unicode_test("\x{263A}"); # (decoded) smiley character
@ -22,7 +20,7 @@ sub unicode_test {
{ # tests for an environment where everything is encoded { # tests for an environment where everything is encoded
my $dbh = connect_ok(sqlite_string_mode => DBD_SQLITE_STRING_MODE_BYTES); my $dbh = connect_ok(sqlite_unicode => 0);
$dbh->do("pragma foreign_keys = on"); $dbh->do("pragma foreign_keys = on");
my $unicode_quoted = $dbh->quote_identifier($unicode_encoded); my $unicode_quoted = $dbh->quote_identifier($unicode_encoded);
$dbh->do("create table $unicode_quoted (id, $unicode_quoted primary key)"); $dbh->do("create table $unicode_quoted (id, $unicode_quoted primary key)");
@ -89,7 +87,7 @@ sub unicode_test {
} }
{ # tests for an environment where everything is decoded { # tests for an environment where everything is decoded
my $dbh = connect_ok(sqlite_string_mode => DBD_SQLITE_STRING_MODE_UNICODE_STRICT); my $dbh = connect_ok(sqlite_unicode => 1);
$dbh->do("pragma foreign_keys = on"); $dbh->do("pragma foreign_keys = on");
my $unicode_quoted = $dbh->quote_identifier($unicode); my $unicode_quoted = $dbh->quote_identifier($unicode);
$dbh->do("create table $unicode_quoted (id, $unicode_quoted primary key)"); $dbh->do("create table $unicode_quoted (id, $unicode_quoted primary key)");

View file

@ -11,10 +11,8 @@ use if -d ".git", "Test::FailWarnings";
BEGIN { requires_unicode_support() } BEGIN { requires_unicode_support() }
use DBD::SQLite::Constants ':dbd_sqlite_string_mode'; my $dbh = connect_ok( sqlite_unicode => 1 );
is( $dbh->{sqlite_unicode}, 1, 'Unicode is on' );
my $dbh = connect_ok( sqlite_string_mode => DBD_SQLITE_STRING_MODE_UNICODE_NAIVE );
is( $dbh->{sqlite_string_mode}, DBD_SQLITE_STRING_MODE_UNICODE_NAIVE, 'Unicode is on' );
ok( $dbh->do(<<'END_SQL'), 'CREATE TABLE' ); ok( $dbh->do(<<'END_SQL'), 'CREATE TABLE' );
CREATE TABLE foo ( CREATE TABLE foo (

View file

@ -184,14 +184,6 @@ my %since = (
TXN_READ => '3034000', TXN_READ => '3034000',
TXN_WRITE => '3034000', TXN_WRITE => '3034000',
IOERR_CORRUPTFS => '3034000', IOERR_CORRUPTFS => '3034000',
SESSION_OBJCONFIG_SIZE => '3036000',
CONSTRAINT_DATATYPE => '3037000',
OPEN_EXRESCODE => '3037000',
NOTICE_RBU => '3041000',
DBCONFIG_STMT_SCANSTATUS => '3042000',
DBCONFIG_REVERSE_SCANORDER => '3042000',
IOERR_IN_PAGE => '3043000',
RESULT_SUBTYPE => '3044001',
status_parameters_for_prepared_statements => '3006004', status_parameters_for_prepared_statements => '3006004',
extended_result_codes => '3006005', extended_result_codes => '3006005',
@ -222,7 +214,6 @@ my %ignore = map {$_ => 1} qw/
OPEN_MAIN_JOURNAL OPEN_TEMP_JOURNAL OPEN_MAIN_JOURNAL OPEN_TEMP_JOURNAL
OPEN_SUBJOURNAL OPEN_MASTER_JOURNAL OPEN_WAL OPEN_SUBJOURNAL OPEN_MASTER_JOURNAL OPEN_WAL
OK_LOAD_PERMANENTLY PREPARE_PERSISTENT OK_LOAD_PERMANENTLY PREPARE_PERSISTENT
SESSION_OBJCONFIG_SIZE
/; /;
my $ignore_tag_re = join '|', ( my $ignore_tag_re = join '|', (
@ -237,9 +228,6 @@ my $ignore_tag_re = join '|', (
'virtual_table_configuration_options', # for sqlite3_vtab_config 'virtual_table_configuration_options', # for sqlite3_vtab_config
'prepare_flags', # for sqlite3_prepare_v3 'prepare_flags', # for sqlite3_prepare_v3
'delete_a_session_object',
'prepared_statement_scan_status',
# status flags (status methods are read-only at the moment) # status flags (status methods are read-only at the moment)
'status_parameters', 'status_parameters',
'status_parameters_for_database_connections', 'status_parameters_for_database_connections',
@ -265,7 +253,6 @@ my $ignore_tag_re = join '|', (
'text_encodings', 'text_encodings',
'virtual_table_constraint_operator_codes', 'virtual_table_constraint_operator_codes',
'virtual_table_indexing_information', 'virtual_table_indexing_information',
'options_for_sqlite3session_object_config',
); );
my %compat = map {$_ => 1} qw/ my %compat = map {$_ => 1} qw/
@ -295,7 +282,7 @@ sub extract_constants {
} }
next; next;
} }
if ($tag && /^#\s*define SQLITE_(\S+)\s+(\d+|\(SQLITE)/) { if ($tag && /^#define SQLITE_(\S+)\s+(\d+|\(SQLITE)/) {
my ($name, $value) = ($1, $2); my ($name, $value) = ($1, $2);
if ($name eq 'VERSION_NUMBER' and $value =~ /^\d+$/) { if ($name eq 'VERSION_NUMBER' and $value =~ /^\d+$/) {
$known_versions{$value} = 1; $known_versions{$value} = 1;
@ -478,9 +465,6 @@ sub year {
my $self = shift; my $self = shift;
return "snapshot" if $self->is_snapshot; return "snapshot" if $self->is_snapshot;
my $version = $self->as_num; my $version = $self->as_num;
return 2024 if $version >= 3450000;
return 2023 if $version >= 3410000;
return 2022 if $version >= 3370200;
return 2021 if $version >= 3340100; return 2021 if $version >= 3340100;
return 2020 if $version >= 3310000; return 2020 if $version >= 3310000;
return 2019 if $version >= 3270000; return 2019 if $version >= 3270000;

View file

@ -17,14 +17,6 @@ my %shorter_tags = (
compile_time_library_version_numbers => 'version', compile_time_library_version_numbers => 'version',
); );
my @dbd_sqlite_constants = (
'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',
);
my %constants = extract_constants(); my %constants = extract_constants();
write_inc(%constants); write_inc(%constants);
write_pm(%constants); write_pm(%constants);
@ -42,14 +34,8 @@ MODULE = DBD::SQLite PACKAGE = DBD::SQLite::Constants
PROTOTYPES: ENABLE PROTOTYPES: ENABLE
BOOT:
END END
for my $constsub (@dbd_sqlite_constants) {
print {$fh} qq< newCONSTSUB( gv_stashpv("DBD::SQLite::Constants", FALSE), "$constsub", newSVuv($constsub) );\n>
}
print $fh "\n";
for my $tag (sort grep !/^_/, keys %constants) { for my $tag (sort grep !/^_/, keys %constants) {
_write_tag($fh, $tag, $constants{$tag}); _write_tag($fh, $tag, $constants{$tag});
} }
@ -158,10 +144,6 @@ use DBD::SQLite;
our \@EXPORT_OK = ( our \@EXPORT_OK = (
END END
for my $const (@dbd_sqlite_constants) {
print {$fh} " '$const',\n";
}
for my $tag (sort keys %constants) { for my $tag (sort keys %constants) {
print $fh <<"END"; print $fh <<"END";
# $tag # $tag
@ -189,14 +171,11 @@ END
my %seen; my %seen;
$constants{all} = [sort grep {!$seen{$_}++} map {@$_} values %constants]; $constants{all} = [sort grep {!$seen{$_}++} map {@$_} values %constants];
push @{$constants{all}}, @dbd_sqlite_constants;
$constants{dbd_sqlite_string_mode} = [grep /^DBD_SQLITE_STRING_MODE_/, @dbd_sqlite_constants];
my $sp = ' ' x 6;
for my $tag (sort keys %constants) { for my $tag (sort keys %constants) {
print $fh <<"END"; print $fh <<"END";
$tag => [qw/ $tag => [qw/
@{[join "\n", map { /^DBD_SQLITE_/ ? "$sp$_" : "${sp}SQLITE_$_"} sort @{$constants{$tag}}]} @{[join "\n", map {" SQLITE_$_"} sort @{$constants{$tag}}]}
/], /],
END END
@ -247,18 +226,11 @@ END
END END
for my $const (@{$constants{$tag}}) { for my $const (@{$constants{$tag}}) {
if ($const =~ /^DBD_SQLITE_/) {
print $fh <<"END";
\=item $const
END
} else {
print $fh <<"END"; print $fh <<"END";
\=item SQLITE_$const \=item SQLITE_$const
END END
} }
}
print $fh <<"END"; print $fh <<"END";
\=back \=back