summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorRobert Kopack <rkopack@tenable.com>2019-07-02 12:59:01 +0200
committerNikita Popov <nikita.ppv@gmail.com>2019-07-02 13:03:35 +0200
commitb546ae986a6efe4daadd23e27f6ccaac5c857e5e (patch)
tree88e99c628daf7ccb82a758219ba66c882d93c423 /ext
parent615ce0b0994206676ad9ab6a7579f1f5cc29ff47 (diff)
downloadphp-git-b546ae986a6efe4daadd23e27f6ccaac5c857e5e.tar.gz
Implement SQLite extended result code functionality
Diffstat (limited to 'ext')
-rw-r--r--ext/pdo_sqlite/pdo_sqlite.c1
-rw-r--r--ext/pdo_sqlite/php_pdo_sqlite_int.h3
-rw-r--r--ext/pdo_sqlite/sqlite_driver.c3
-rw-r--r--ext/pdo_sqlite/tests/pdo_sqlite_extendederror_attr.phpt50
-rw-r--r--ext/sqlite3/sqlite3.c96
-rw-r--r--ext/sqlite3/tests/sqlite3_38_extended_error.phpt36
-rw-r--r--ext/sqlite3/tests/sqlite3_39_toggleExtended.phpt43
7 files changed, 211 insertions, 21 deletions
diff --git a/ext/pdo_sqlite/pdo_sqlite.c b/ext/pdo_sqlite/pdo_sqlite.c
index 82e2d79b06..5c2fd63cdb 100644
--- a/ext/pdo_sqlite/pdo_sqlite.c
+++ b/ext/pdo_sqlite/pdo_sqlite.c
@@ -76,6 +76,7 @@ PHP_MINIT_FUNCTION(pdo_sqlite)
REGISTER_PDO_CLASS_CONST_LONG("SQLITE_OPEN_READWRITE", (zend_long)SQLITE_OPEN_READWRITE);
REGISTER_PDO_CLASS_CONST_LONG("SQLITE_OPEN_CREATE", (zend_long)SQLITE_OPEN_CREATE);
REGISTER_PDO_CLASS_CONST_LONG("SQLITE_ATTR_READONLY_STATEMENT", (zend_long)PDO_SQLITE_ATTR_READONLY_STATEMENT);
+ REGISTER_PDO_CLASS_CONST_LONG("SQLITE_ATTR_EXTENDED_RESULT_CODES", (zend_long)PDO_SQLITE_ATTR_EXTENDED_RESULT_CODES);
return php_pdo_register_driver(&pdo_sqlite_driver);
}
diff --git a/ext/pdo_sqlite/php_pdo_sqlite_int.h b/ext/pdo_sqlite/php_pdo_sqlite_int.h
index e784294dbc..c1d3a953a0 100644
--- a/ext/pdo_sqlite/php_pdo_sqlite_int.h
+++ b/ext/pdo_sqlite/php_pdo_sqlite_int.h
@@ -76,7 +76,8 @@ extern const struct pdo_stmt_methods sqlite_stmt_methods;
enum {
PDO_SQLITE_ATTR_OPEN_FLAGS = PDO_ATTR_DRIVER_SPECIFIC,
- PDO_SQLITE_ATTR_READONLY_STATEMENT
+ PDO_SQLITE_ATTR_READONLY_STATEMENT,
+ PDO_SQLITE_ATTR_EXTENDED_RESULT_CODES
};
#endif
diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c
index ab65049a96..120488e229 100644
--- a/ext/pdo_sqlite/sqlite_driver.c
+++ b/ext/pdo_sqlite/sqlite_driver.c
@@ -305,6 +305,9 @@ static int pdo_sqlite_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val)
case PDO_ATTR_TIMEOUT:
sqlite3_busy_timeout(H->db, zval_get_long(val) * 1000);
return 1;
+ case PDO_SQLITE_ATTR_EXTENDED_RESULT_CODES:
+ sqlite3_extended_result_codes(H->db, zval_get_long(val));
+ return 1;
}
return 0;
}
diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_extendederror_attr.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_extendederror_attr.phpt
new file mode 100644
index 0000000000..50b939b6eb
--- /dev/null
+++ b/ext/pdo_sqlite/tests/pdo_sqlite_extendederror_attr.phpt
@@ -0,0 +1,50 @@
+--TEST--
+PDO_sqlite: Testing PDO_SQLITE_ATTR_EXTENDED_RESULT_CODES
+--SKIPIF--
+<?php if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?>
+--FILE--
+<?php
+
+echo "Creating new PDO" . PHP_EOL;
+$db = new PDO('sqlite::memory:');
+
+$db->exec("CREATE TABLE dog ( id INTEGER PRIMARY KEY, name TEXT, annoying INTEGER )");
+
+echo "Inserting first time which should succeed" . PHP_EOL;
+$db->exec("INSERT INTO dog VALUES (1, 'Annoying Dog', 1)");
+$errorInfo = $db->errorInfo();
+echo sprintf("First Error Info: SQLSTATE Error Code: (%s), Driver Specific Error Code: (%s)", $errorInfo[0], $errorInfo[1]) . PHP_EOL;
+
+echo "Inserting second time which should fail" . PHP_EOL;
+$result = $db->exec("INSERT INTO dog VALUES (1, 'Annoying Dog', 1)");
+$errorInfo = $db->errorInfo();
+echo sprintf("Second Error Info: SQLSTATE Error Code: (%s), Driver Specific Error Code: (%s)", $errorInfo[0], $errorInfo[1]) . PHP_EOL;
+
+
+echo "Creating new PDO with Extended Result Codes turned on" . PHP_EOL;
+$db = new PDO('sqlite::memory:', '', '', [PDO::SQLITE_ATTR_EXTENDED_RESULT_CODES => TRUE]);
+
+$db->exec("CREATE TABLE dog ( id INTEGER PRIMARY KEY, name TEXT, annoying INTEGER )");
+
+echo "Inserting first time which should succeed" . PHP_EOL;
+$result = $db->exec("INSERT INTO dog VALUES (1, 'Annoying Dog', 1)");
+$errorInfo = $db->errorInfo();
+echo sprintf("First (Extended) Error Info: SQLSTATE Error Code: (%s), Driver Specific Error Code: (%s)", $errorInfo[0], $errorInfo[1]) . PHP_EOL;
+
+echo "Inserting second time which should fail" . PHP_EOL;
+$result = $db->exec("INSERT INTO dog VALUES (1, 'Annoying Dog', 1)");
+$errorInfo = $db->errorInfo();
+echo sprintf("Second (Extended) Error Info: SQLSTATE Error Code: (%s), Driver Specific Error Code: (%s)", $errorInfo[0], $errorInfo[1]) . PHP_EOL;
+
+?>
+--EXPECT--
+Creating new PDO
+Inserting first time which should succeed
+First Error Info: SQLSTATE Error Code: (00000), Driver Specific Error Code: ()
+Inserting second time which should fail
+Second Error Info: SQLSTATE Error Code: (23000), Driver Specific Error Code: (19)
+Creating new PDO with Extended Result Codes turned on
+Inserting first time which should succeed
+First (Extended) Error Info: SQLSTATE Error Code: (00000), Driver Specific Error Code: ()
+Inserting second time which should fail
+Second (Extended) Error Info: SQLSTATE Error Code: (HY000), Driver Specific Error Code: (1555)
diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c
index e3474e4acb..429be63cb6 100644
--- a/ext/sqlite3/sqlite3.c
+++ b/ext/sqlite3/sqlite3.c
@@ -289,6 +289,56 @@ PHP_METHOD(sqlite3, lastErrorCode)
}
/* }}} */
+/* {{{ proto int SQLite3::lastExtendedErrorCode()
+ Returns the numeric extended result code of the most recent failed sqlite API call for the database connection. */
+PHP_METHOD(sqlite3, lastExtendedErrorCode)
+{
+ php_sqlite3_db_object *db_obj;
+ zval *object = ZEND_THIS;
+ db_obj = Z_SQLITE3_DB_P(object);
+
+ SQLITE3_CHECK_INITIALIZED(db_obj, db_obj->db, SQLite3)
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (db_obj->initialised) {
+ RETURN_LONG(sqlite3_extended_errcode(db_obj->db));
+ } else {
+ RETURN_LONG(0);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool SQLite3::enableExtendedResultCodes([bool enable = true])
+ Turns on or off the extended result codes feature of SQLite. */
+PHP_METHOD(sqlite3, enableExtendedResultCodes)
+{
+ php_sqlite3_db_object *db_obj;
+ zval *object = ZEND_THIS;
+ zend_bool enable = 1;
+ db_obj = Z_SQLITE3_DB_P(object);
+ int ret;
+
+ SQLITE3_CHECK_INITIALIZED(db_obj, db_obj->db, SQLite3)
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable) == FAILURE) {
+ return;
+ }
+
+ if (db_obj->initialised) {
+ ret = sqlite3_extended_result_codes(db_obj->db, enable ? 1 : 0);
+ if (ret == SQLITE_OK)
+ {
+ RETURN_TRUE;
+ }
+ }
+
+ RETURN_FALSE;
+}
+/* }}} */
+
/* {{{ proto string SQLite3::lastErrorMsg()
Returns english text describing the most recent failed sqlite API call for the database connection. */
PHP_METHOD(sqlite3, lastErrorMsg)
@@ -2157,35 +2207,41 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite3result_fetcharray, 0, 0, 0)
ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite3_enableextended, 0, 0, 1)
+ ZEND_ARG_INFO(0, enable)
+ZEND_END_ARG_INFO()
+
ZEND_BEGIN_ARG_INFO(arginfo_sqlite3_void, 0)
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ php_sqlite3_class_methods */
static const zend_function_entry php_sqlite3_class_methods[] = {
- PHP_ME(sqlite3, open, arginfo_sqlite3_open, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, close, arginfo_sqlite3_void, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, exec, arginfo_sqlite3_query, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, version, arginfo_sqlite3_void, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_ME(sqlite3, lastInsertRowID, arginfo_sqlite3_void, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, lastErrorCode, arginfo_sqlite3_void, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, lastErrorMsg, arginfo_sqlite3_void, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, busyTimeout, arginfo_sqlite3_busytimeout, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, open, arginfo_sqlite3_open, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, close, arginfo_sqlite3_void, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, exec, arginfo_sqlite3_query, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, version, arginfo_sqlite3_void, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+ PHP_ME(sqlite3, lastInsertRowID, arginfo_sqlite3_void, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, lastErrorCode, arginfo_sqlite3_void, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, lastExtendedErrorCode, arginfo_sqlite3_void, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, enableExtendedResultCodes, arginfo_sqlite3_enableextended, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, lastErrorMsg, arginfo_sqlite3_void, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, busyTimeout, arginfo_sqlite3_busytimeout, ZEND_ACC_PUBLIC)
#ifndef SQLITE_OMIT_LOAD_EXTENSION
- PHP_ME(sqlite3, loadExtension, arginfo_sqlite3_loadextension, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, loadExtension, arginfo_sqlite3_loadextension, ZEND_ACC_PUBLIC)
#endif
- PHP_ME(sqlite3, changes, arginfo_sqlite3_void, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, escapeString, arginfo_sqlite3_escapestring, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_ME(sqlite3, prepare, arginfo_sqlite3_query, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, query, arginfo_sqlite3_query, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, querySingle, arginfo_sqlite3_querysingle, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, createFunction, arginfo_sqlite3_createfunction, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, createAggregate, arginfo_sqlite3_createaggregate, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, createCollation, arginfo_sqlite3_createcollation, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, openBlob, arginfo_sqlite3_openblob, ZEND_ACC_PUBLIC)
- PHP_ME(sqlite3, enableExceptions, arginfo_sqlite3_enableexceptions, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, changes, arginfo_sqlite3_void, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, escapeString, arginfo_sqlite3_escapestring, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+ PHP_ME(sqlite3, prepare, arginfo_sqlite3_query, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, query, arginfo_sqlite3_query, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, querySingle, arginfo_sqlite3_querysingle, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, createFunction, arginfo_sqlite3_createfunction, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, createAggregate, arginfo_sqlite3_createaggregate, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, createCollation, arginfo_sqlite3_createcollation, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, openBlob, arginfo_sqlite3_openblob, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, enableExceptions, arginfo_sqlite3_enableexceptions, ZEND_ACC_PUBLIC)
#if SQLITE_VERSION_NUMBER >= 3006011
- PHP_ME(sqlite3, backup, arginfo_sqlite3_backup, ZEND_ACC_PUBLIC)
+ PHP_ME(sqlite3, backup, arginfo_sqlite3_backup, ZEND_ACC_PUBLIC)
#endif
/* Aliases */
PHP_MALIAS(sqlite3, __construct, open, arginfo_sqlite3_open, ZEND_ACC_PUBLIC)
diff --git a/ext/sqlite3/tests/sqlite3_38_extended_error.phpt b/ext/sqlite3/tests/sqlite3_38_extended_error.phpt
new file mode 100644
index 0000000000..8c16889c53
--- /dev/null
+++ b/ext/sqlite3/tests/sqlite3_38_extended_error.phpt
@@ -0,0 +1,36 @@
+--TEST--
+SQLite3 extended error code Function
+--SKIPIF--
+<?php require_once(__DIR__ . '/skipif.inc'); ?>
+--FILE--
+<?php
+
+require_once(__DIR__ . '/new_db.inc');
+
+$db->query("CREATE TABLE dog ( id INTEGER PRIMARY KEY, name TEXT, annoying INTEGER )");
+
+echo "Inserting first time which should succeed" . PHP_EOL;
+$result = $db->query("INSERT INTO dog VALUES (1, 'Annoying Dog', 1)");
+echo "First Error Code: " . $db->lastErrorCode() . PHP_EOL;
+
+echo "Inserting second time which should fail" . PHP_EOL;
+$result = $db->query("INSERT INTO dog VALUES (1, 'Annoying Dog', 1)");
+echo "Second Error Code: " . $db->lastErrorCode() . PHP_EOL;
+echo "Second Extended Error Code: " . $db->lastExtendedErrorCode() . PHP_EOL;
+
+echo "Closing database\n";
+var_dump($db->close());
+echo "Done" . PHP_EOL;
+?>
+--EXPECTF--
+Inserting first time which should succeed
+First Error Code: 0
+Inserting second time which should fail
+
+Warning: SQLite3::query(): Unable to execute statement: UNIQUE constraint failed: dog.id in %s on line %d
+Second Error Code: 19
+Second Extended Error Code: 1555
+Closing database
+bool(true)
+Done
+
diff --git a/ext/sqlite3/tests/sqlite3_39_toggleExtended.phpt b/ext/sqlite3/tests/sqlite3_39_toggleExtended.phpt
new file mode 100644
index 0000000000..6c2240e3d7
--- /dev/null
+++ b/ext/sqlite3/tests/sqlite3_39_toggleExtended.phpt
@@ -0,0 +1,43 @@
+--TEST--
+SQLite3 enable Extended Error Result Codes
+--SKIPIF--
+<?php require_once(__DIR__ . '/skipif.inc'); ?>
+--FILE--
+<?php
+
+require_once(__DIR__ . '/new_db.inc');
+
+$db->query("CREATE TABLE dog ( id INTEGER PRIMARY KEY, name TEXT, annoying INTEGER )");
+
+echo "Inserting first time which should succeed" . PHP_EOL;
+$result = $db->query("INSERT INTO dog VALUES (1, 'Annoying Dog', 1)");
+echo "First Error Code: " . $db->lastErrorCode() . PHP_EOL;
+
+echo "Inserting second time which should fail" . PHP_EOL;
+$result = $db->query("INSERT INTO dog VALUES (1, 'Annoying Dog', 1)");
+echo "Second Error Code: " . $db->lastErrorCode() . PHP_EOL;
+
+echo "Toggling extended error codes and re-inserting a third time" . PHP_EOL;
+$db->enableExtendedResultCodes(true);
+$result = $db->query("INSERT INTO DOG VALUES (1, 'Annoying Dog', 1)");
+echo "Third (Extended) Error Code: " . $db->lastErrorCode() . PHP_EOL;
+
+echo "Closing database\n";
+var_dump($db->close());
+echo "Done" . PHP_EOL;
+?>
+--EXPECTF--
+Inserting first time which should succeed
+First Error Code: 0
+Inserting second time which should fail
+
+Warning: SQLite3::query(): Unable to execute statement: UNIQUE constraint failed: dog.id in %s on line %d
+Second Error Code: 19
+Toggling extended error codes and re-inserting a third time
+
+Warning: SQLite3::query(): Unable to execute statement: UNIQUE constraint failed: dog.id in %s on line %d
+Third (Extended) Error Code: 1555
+Closing database
+bool(true)
+Done
+