diff options
| author | Robert Kopack <rkopack@tenable.com> | 2019-07-02 12:59:01 +0200 |
|---|---|---|
| committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-07-02 13:03:35 +0200 |
| commit | b546ae986a6efe4daadd23e27f6ccaac5c857e5e (patch) | |
| tree | 88e99c628daf7ccb82a758219ba66c882d93c423 | |
| parent | 615ce0b0994206676ad9ab6a7579f1f5cc29ff47 (diff) | |
| download | php-git-b546ae986a6efe4daadd23e27f6ccaac5c857e5e.tar.gz | |
Implement SQLite extended result code functionality
| -rw-r--r-- | UPGRADING | 8 | ||||
| -rw-r--r-- | ext/pdo_sqlite/pdo_sqlite.c | 1 | ||||
| -rw-r--r-- | ext/pdo_sqlite/php_pdo_sqlite_int.h | 3 | ||||
| -rw-r--r-- | ext/pdo_sqlite/sqlite_driver.c | 3 | ||||
| -rw-r--r-- | ext/pdo_sqlite/tests/pdo_sqlite_extendederror_attr.phpt | 50 | ||||
| -rw-r--r-- | ext/sqlite3/sqlite3.c | 96 | ||||
| -rw-r--r-- | ext/sqlite3/tests/sqlite3_38_extended_error.phpt | 36 | ||||
| -rw-r--r-- | ext/sqlite3/tests/sqlite3_39_toggleExtended.phpt | 43 |
8 files changed, 219 insertions, 21 deletions
@@ -265,6 +265,14 @@ PHP 7.4 UPGRADE NOTES . PDOStatement::getAttribute(PDO::SQLITE_ATTR_READONLY_STATEMENT) allows to check whether this statement is read-only, i.e. whether it doesn't modify the database. + . PDO::setAttribute(PDO::SQLITE_ATTR_EXTENDED_RESULT_CODES, true) enables the + use of SQLite3 extended result codes in errorInfo(). + +r SQLite3: + . Added SQLite3::lastExtendedErrorCode() to fetch the last extended result + code. + . Added SQLite3::enableExtendedResultCodes($enable = true), which will make + SQLite3::lastErrorCode() return extended result codes. - Standard: . strip_tags() now also accepts an array of allowed tags: Instead of 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 + |
