1
0
Fork 0
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:
Kenichi Ishigaki 2015-02-16 17:41:42 +09:00
parent 5ddbdd1e6b
commit 7a234eb71b
3 changed files with 193 additions and 80 deletions

View file

@ -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
View file

@ -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);
}
}

View file

@ -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;