mirror of
https://github.com/DBD-SQLite/DBD-SQLite
synced 2025-06-07 14:19:10 -04:00
implemented a "do" shortcut for a special case (no attr, no bind params) (RT-35449)
This commit is contained in:
parent
5ddbdd1e6b
commit
7a234eb71b
3 changed files with 193 additions and 80 deletions
18
SQLite.xs
18
SQLite.xs
|
@ -12,6 +12,24 @@ BOOT:
|
|||
sv_setpv(get_sv("DBD::SQLite::sqlite_version", TRUE|GV_ADDMULTI), SQLITE_VERSION);
|
||||
sv_setiv(get_sv("DBD::SQLite::sqlite_version_number", TRUE|GV_ADDMULTI), SQLITE_VERSION_NUMBER);
|
||||
|
||||
void
|
||||
_do(dbh, statement)
|
||||
SV *dbh
|
||||
SV *statement
|
||||
CODE:
|
||||
{
|
||||
D_imp_dbh(dbh);
|
||||
IV retval;
|
||||
retval = sqlite_db_do_sv(dbh, imp_dbh, statement);
|
||||
/* remember that dbd_db_do_sv must return <= -2 for error */
|
||||
if (retval == 0) /* ok with no rows affected */
|
||||
XST_mPV(0, "0E0"); /* (true but zero) */
|
||||
else if (retval < -1) /* -1 == unknown number of rows */
|
||||
XST_mUNDEF(0); /* <= -2 means error */
|
||||
else
|
||||
XST_mIV(0, retval); /* typically 1, rowcount or -1 */
|
||||
}
|
||||
|
||||
IV
|
||||
last_insert_rowid(dbh)
|
||||
SV *dbh
|
||||
|
|
245
dbdimp.c
245
dbdimp.c
|
@ -41,6 +41,97 @@ static int last_dbh_is_unicode; /* see _last_dbh_is_unicode() */
|
|||
#define sqlite_open2(dbname,db,flags) _sqlite_open(aTHX_ dbh, dbname, db, flags)
|
||||
#define _isspace(c) (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f')
|
||||
|
||||
#define _skip_whitespaces(sql) \
|
||||
while ( _isspace(sql[0]) || (sql[0] == '-' && sql[1] == '-')) { \
|
||||
if ( _isspace(sql[0]) ) { \
|
||||
while ( _isspace(sql[0]) ) sql++; \
|
||||
continue; \
|
||||
} \
|
||||
else if (sql[0] == '-') { \
|
||||
while ( sql[0] != 0 && sql[0] != '\n' ) sql++; \
|
||||
continue; \
|
||||
} \
|
||||
}
|
||||
|
||||
bool
|
||||
_starts_with_begin(const char *sql) {
|
||||
return (
|
||||
(sql[0] == 'B' || sql[0] == 'b') &&
|
||||
(sql[1] == 'E' || sql[1] == 'e') &&
|
||||
(sql[2] == 'G' || sql[2] == 'g') &&
|
||||
(sql[3] == 'I' || sql[3] == 'i') &&
|
||||
(sql[4] == 'N' || sql[4] == 'n')
|
||||
) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
bool
|
||||
_starts_with_commit(const char *sql) {
|
||||
return (
|
||||
((sql[0] == 'C' || sql[0] == 'c') &&
|
||||
(sql[1] == 'O' || sql[1] == 'o') &&
|
||||
(sql[2] == 'M' || sql[2] == 'm') &&
|
||||
(sql[3] == 'M' || sql[3] == 'm') &&
|
||||
(sql[4] == 'I' || sql[4] == 'i') &&
|
||||
(sql[5] == 'T' || sql[5] == 't')) ||
|
||||
((sql[0] == 'E' || sql[0] == 'e') &&
|
||||
(sql[1] == 'N' || sql[1] == 'n') &&
|
||||
(sql[2] == 'D' || sql[2] == 'd'))
|
||||
) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
bool
|
||||
_starts_with_rollback(const char *sql) {
|
||||
int i;
|
||||
if (
|
||||
(sql[0] == 'R' || sql[0] == 'r') &&
|
||||
(sql[1] == 'O' || sql[1] == 'o') &&
|
||||
(sql[2] == 'L' || sql[2] == 'l') &&
|
||||
(sql[3] == 'L' || sql[3] == 'l') &&
|
||||
(sql[4] == 'B' || sql[4] == 'b') &&
|
||||
(sql[5] == 'A' || sql[5] == 'a') &&
|
||||
(sql[6] == 'C' || sql[6] == 'c') &&
|
||||
(sql[7] == 'K' || sql[7] == 'k')) {
|
||||
int l = strlen(sql);
|
||||
bool is_savepoint = FALSE;
|
||||
for(i = 8; i < l; i++) {
|
||||
if (_isspace(sql[i])) continue;
|
||||
if (sql[i] == '-' && sql[i+1] == '-') {
|
||||
while (sql[i] != 0 && sql[i] != '\n') i++;
|
||||
continue;
|
||||
}
|
||||
if (sql[i] == 'T' || sql[i] == 't') {
|
||||
if (
|
||||
(sql[i+0] == 'T' || sql[i+0] == 't') &&
|
||||
(sql[i+1] == 'R' || sql[i+1] == 'r') &&
|
||||
(sql[i+2] == 'A' || sql[i+2] == 'a') &&
|
||||
(sql[i+3] == 'N' || sql[i+3] == 'n') &&
|
||||
(sql[i+4] == 'S' || sql[i+4] == 's') &&
|
||||
(sql[i+5] == 'A' || sql[i+5] == 'a') &&
|
||||
(sql[i+6] == 'C' || sql[i+6] == 'c') &&
|
||||
(sql[i+7] == 'T' || sql[i+7] == 't') &&
|
||||
(sql[i+8] == 'I' || sql[i+8] == 'i') &&
|
||||
(sql[i+9] == 'O' || sql[i+9] == 'o') &&
|
||||
(sql[i+10] == 'N' || sql[i+10] == 'n')) {
|
||||
i += 10; continue;
|
||||
}
|
||||
else if (
|
||||
(sql[i+0] == 'T' || sql[i+0] == 't') &&
|
||||
(sql[i+1] == 'O' || sql[i+1] == 'o') &&
|
||||
(sql[i+2] == ' ' || sql[i+2] == '\t')) {
|
||||
/* rolling back to a savepoint should not
|
||||
change AutoCommit status */
|
||||
is_savepoint = TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!is_savepoint) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* adopted from sqlite3.c */
|
||||
|
||||
#define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
|
||||
|
@ -427,6 +518,73 @@ sqlite_db_login6(SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *user, char *pa
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
sqlite_db_do_sv(SV *dbh, imp_dbh_t *imp_dbh, SV *sv_statement)
|
||||
{
|
||||
dTHX;
|
||||
int rc = 0;
|
||||
int i;
|
||||
char *statement;
|
||||
|
||||
if (!DBIc_ACTIVE(imp_dbh)) {
|
||||
sqlite_error(dbh, -2, "attempt to do on inactive database handle");
|
||||
return -2; /* -> undef in SQLite.xsi */
|
||||
}
|
||||
|
||||
/* sqlite3_prepare wants an utf8-encoded SQL statement */
|
||||
if (imp_dbh->unicode) {
|
||||
sv_utf8_upgrade(sv_statement);
|
||||
}
|
||||
|
||||
statement = SvPV_nolen(sv_statement);
|
||||
|
||||
sqlite_trace(dbh, imp_dbh, 3, form("do statement: %s", statement));
|
||||
|
||||
croak_if_db_is_null();
|
||||
|
||||
if (sqlite3_get_autocommit(imp_dbh->db)) {
|
||||
const char *sql = statement;
|
||||
_skip_whitespaces(sql);
|
||||
if (_starts_with_begin(sql)) {
|
||||
if (DBIc_is(imp_dbh, DBIcf_AutoCommit)) {
|
||||
DBIc_on(imp_dbh, DBIcf_BegunWork);
|
||||
DBIc_off(imp_dbh, DBIcf_AutoCommit);
|
||||
}
|
||||
}
|
||||
else if (!DBIc_is(imp_dbh, DBIcf_AutoCommit)) {
|
||||
sqlite_trace(dbh, imp_dbh, 3, "BEGIN TRAN");
|
||||
if (imp_dbh->use_immediate_transaction) {
|
||||
rc = sqlite_exec(dbh, "BEGIN IMMEDIATE TRANSACTION");
|
||||
} else {
|
||||
rc = sqlite_exec(dbh, "BEGIN TRANSACTION");
|
||||
}
|
||||
if (rc != SQLITE_OK) {
|
||||
return -2; /* -> undef in SQLite.xsi */
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (DBIc_is(imp_dbh, DBIcf_BegunWork)) {
|
||||
const char *sql = statement;
|
||||
_skip_whitespaces(sql);
|
||||
if (_starts_with_commit(sql)) {
|
||||
DBIc_off(imp_dbh, DBIcf_BegunWork);
|
||||
DBIc_on(imp_dbh, DBIcf_AutoCommit);
|
||||
}
|
||||
else if (_starts_with_rollback(sql)) {
|
||||
DBIc_off(imp_dbh, DBIcf_BegunWork);
|
||||
DBIc_on(imp_dbh, DBIcf_AutoCommit);
|
||||
}
|
||||
}
|
||||
|
||||
rc = sqlite_exec(dbh, statement);
|
||||
if (rc != SQLITE_OK) {
|
||||
sqlite_error(dbh, rc, sqlite3_errmsg(imp_dbh->db));
|
||||
return -2;
|
||||
}
|
||||
|
||||
return sqlite3_changes(imp_dbh->db);
|
||||
}
|
||||
|
||||
int
|
||||
sqlite_db_commit(SV *dbh, imp_dbh_t *imp_dbh)
|
||||
{
|
||||
|
@ -859,21 +1017,8 @@ sqlite_st_execute(SV *sth, imp_sth_t *imp_sth)
|
|||
if (sqlite3_get_autocommit(imp_dbh->db)) {
|
||||
/* COMPAT: sqlite3_sql is only available for 3006000 or newer */
|
||||
const char *sql = sqlite3_sql(imp_sth->stmt);
|
||||
while ( _isspace(sql[0]) || (sql[0] == '-' && sql[1] == '-')) {
|
||||
if ( _isspace(sql[0]) ) {
|
||||
while ( _isspace(sql[0]) ) sql++;
|
||||
continue;
|
||||
}
|
||||
else if (sql[0] == '-') {
|
||||
while ( sql[0] != 0 && sql[0] != '\n' ) sql++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((sql[0] == 'B' || sql[0] == 'b') &&
|
||||
(sql[1] == 'E' || sql[1] == 'e') &&
|
||||
(sql[2] == 'G' || sql[2] == 'g') &&
|
||||
(sql[3] == 'I' || sql[3] == 'i') &&
|
||||
(sql[4] == 'N' || sql[4] == 'n')) {
|
||||
_skip_whitespaces(sql);
|
||||
if (_starts_with_begin(sql)) {
|
||||
if (DBIc_is(imp_dbh, DBIcf_AutoCommit)) {
|
||||
DBIc_on(imp_dbh, DBIcf_BegunWork);
|
||||
DBIc_off(imp_dbh, DBIcf_AutoCommit);
|
||||
|
@ -894,74 +1039,14 @@ sqlite_st_execute(SV *sth, imp_sth_t *imp_sth)
|
|||
else if (DBIc_is(imp_dbh, DBIcf_BegunWork)) {
|
||||
/* COMPAT: sqlite3_sql is only available for 3006000 or newer */
|
||||
const char *sql = sqlite3_sql(imp_sth->stmt);
|
||||
while ( _isspace(sql[0]) || (sql[0] == '-' && sql[1] == '-')) {
|
||||
if ( _isspace(sql[0]) ) {
|
||||
while ( _isspace(sql[0]) ) sql++;
|
||||
continue;
|
||||
}
|
||||
else if (sql[0] == '-') {
|
||||
while ( sql[0] != 0 && sql[0] != '\n' ) sql++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (((sql[0] == 'C' || sql[0] == 'c') &&
|
||||
(sql[1] == 'O' || sql[1] == 'o') &&
|
||||
(sql[2] == 'M' || sql[2] == 'm') &&
|
||||
(sql[3] == 'M' || sql[3] == 'm') &&
|
||||
(sql[4] == 'I' || sql[4] == 'i') &&
|
||||
(sql[5] == 'T' || sql[5] == 't')) ||
|
||||
((sql[0] == 'E' || sql[0] == 'e') &&
|
||||
(sql[1] == 'N' || sql[1] == 'n') &&
|
||||
(sql[2] == 'D' || sql[2] == 'd'))) {
|
||||
_skip_whitespaces(sql);
|
||||
if (_starts_with_commit(sql)) {
|
||||
DBIc_off(imp_dbh, DBIcf_BegunWork);
|
||||
DBIc_on(imp_dbh, DBIcf_AutoCommit);
|
||||
}
|
||||
else if (
|
||||
((sql[0] == 'R' || sql[0] == 'r') &&
|
||||
(sql[1] == 'O' || sql[1] == 'o') &&
|
||||
(sql[2] == 'L' || sql[2] == 'l') &&
|
||||
(sql[3] == 'L' || sql[3] == 'l') &&
|
||||
(sql[4] == 'B' || sql[4] == 'b') &&
|
||||
(sql[5] == 'A' || sql[5] == 'a') &&
|
||||
(sql[6] == 'C' || sql[6] == 'c') &&
|
||||
(sql[7] == 'K' || sql[7] == 'k'))) {
|
||||
int l = strlen(sql);
|
||||
bool is_savepoint = FALSE;
|
||||
for(i = 8; i < l; i++) {
|
||||
if (_isspace(sql[i])) continue;
|
||||
if (sql[i] == '-' && sql[i+1] == '-') {
|
||||
while (sql[i] != 0 && sql[i] != '\n') i++;
|
||||
continue;
|
||||
}
|
||||
if (sql[i] == 'T' || sql[i] == 't') {
|
||||
if ((sql[i+0] == 'T' || sql[i+0] == 't') &&
|
||||
(sql[i+1] == 'R' || sql[i+1] == 'r') &&
|
||||
(sql[i+2] == 'A' || sql[i+2] == 'a') &&
|
||||
(sql[i+3] == 'N' || sql[i+3] == 'n') &&
|
||||
(sql[i+4] == 'S' || sql[i+4] == 's') &&
|
||||
(sql[i+5] == 'A' || sql[i+5] == 'a') &&
|
||||
(sql[i+6] == 'C' || sql[i+6] == 'c') &&
|
||||
(sql[i+7] == 'T' || sql[i+7] == 't') &&
|
||||
(sql[i+8] == 'I' || sql[i+8] == 'i') &&
|
||||
(sql[i+9] == 'O' || sql[i+9] == 'o') &&
|
||||
(sql[i+10] == 'N' || sql[i+10] == 'n')) {
|
||||
i += 10; continue;
|
||||
}
|
||||
else if (
|
||||
(sql[i+0] == 'T' || sql[i+0] == 't') &&
|
||||
(sql[i+1] == 'O' || sql[i+1] == 'o') &&
|
||||
(sql[i+2] == ' ' || sql[i+2] == '\t')) {
|
||||
/* rolling back to a savepoint should not
|
||||
change AutoCommit status */
|
||||
is_savepoint = TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!is_savepoint) {
|
||||
DBIc_off(imp_dbh, DBIcf_BegunWork);
|
||||
DBIc_on(imp_dbh, DBIcf_AutoCommit);
|
||||
}
|
||||
else if (_starts_with_rollback(sql)) {
|
||||
DBIc_off(imp_dbh, DBIcf_BegunWork);
|
||||
DBIc_on(imp_dbh, DBIcf_AutoCommit);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -205,6 +205,16 @@ sub prepare {
|
|||
sub do {
|
||||
my ($dbh, $statement, $attr, @bind_values) = @_;
|
||||
|
||||
# shortcut
|
||||
if (defined $statement && !defined $attr && !@bind_values) {
|
||||
# _do() (i.e. sqlite3_exec()) runs semicolon-separate SQL
|
||||
# statements, which is handy but insecure sometimes.
|
||||
# Use this only when it's safe or explicitly allowed.
|
||||
if (index($statement, ';') == -1 or $dbh->FETCH('sqlite_allow_multiple_statements')) {
|
||||
return DBD::SQLite::db::_do($dbh, $statement);
|
||||
}
|
||||
}
|
||||
|
||||
my @copy = @{[@bind_values]};
|
||||
my $rows = 0;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue