Skip to content

ext/pdo_sqlite: EXPLAIN mode support for SQL statements. #18829

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions ext/pdo_sqlite/pdo_sqlite.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ class Sqlite extends \PDO
/** @cvalue PDO_SQLITE_ATTR_BUSY_STATEMENT */
public const int ATTR_BUSY_STATEMENT = UNKNOWN;

/** @cvalue PDO_SQLITE_ATTR_EXPLAIN_STATEMENT */
public const int ATTR_EXPLAIN_STATEMENT = UNKNOWN;

#if SQLITE_VERSION_NUMBER >= 3041000
public const int EXPLAIN_MODE_PREPARED = 0;
public const int EXPLAIN_MODE_EXPLAIN = 1;
public const int EXPLAIN_MODE_EXPLAIN_QUERY_PLAN = 2;
#endif

/** @cvalue SQLITE_OK */
public const int OK = UNKNOWN;

Expand Down
32 changes: 31 additions & 1 deletion ext/pdo_sqlite/pdo_sqlite_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion ext/pdo_sqlite/php_pdo_sqlite_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ enum {
PDO_SQLITE_ATTR_OPEN_FLAGS = PDO_ATTR_DRIVER_SPECIFIC,
PDO_SQLITE_ATTR_READONLY_STATEMENT,
PDO_SQLITE_ATTR_EXTENDED_RESULT_CODES,
PDO_SQLITE_ATTR_BUSY_STATEMENT
PDO_SQLITE_ATTR_BUSY_STATEMENT,
PDO_SQLITE_ATTR_EXPLAIN_STATEMENT
};

typedef int pdo_sqlite_create_collation_callback(void*, int, const void*, int, const void*);
Expand Down
64 changes: 63 additions & 1 deletion ext/pdo_sqlite/sqlite_statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
#include "php_pdo_sqlite.h"
#include "php_pdo_sqlite_int.h"

#if defined(__APPLE__)
// If more than one usage, a Zend macro could be created
// around this runtime check
#include <Availability.h>
#endif

static int pdo_sqlite_stmt_dtor(pdo_stmt_t *stmt)
{
Expand Down Expand Up @@ -387,21 +392,78 @@ static int pdo_sqlite_stmt_get_attribute(pdo_stmt_t *stmt, zend_long attr, zval
ZVAL_TRUE(val);
}
break;
case PDO_SQLITE_ATTR_EXPLAIN_STATEMENT:
#if SQLITE_VERSION_NUMBER >= 3041000
#if defined(__APPLE__)
if (__builtin_available(macOS 14.2, *)) {
#endif
ZVAL_LONG(val, (zend_long)sqlite3_stmt_isexplain(S->stmt));
return 1;
#if defined(__APPLE__)
} else {
zend_value_error("explain statement unsupported");
return 0;
}
#endif
#else
zend_value_error("explain statement unsupported");
return 0;
#endif
default:
return 0;
}

return 1;
}

static int pdo_sqlite_stmt_set_attribute(pdo_stmt_t *stmt, zend_long attr, zval *zval)
{
pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;

switch (attr) {
case PDO_SQLITE_ATTR_EXPLAIN_STATEMENT:
#if SQLITE_VERSION_NUMBER >= 3041000
#if defined(__APPLE__)
if (__builtin_available(macOS 14.2, *)) {
#endif
if (Z_TYPE_P(zval) != IS_LONG) {
zend_type_error("explain mode must be of type int, %s given", zend_zval_value_name(zval));
return 0;
}
if (Z_LVAL_P(zval) < 0 || Z_LVAL_P(zval) > 2) {
zend_value_error("explain mode must be one of the EXPLAIN_MODE_* constants");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For class constants we normally prefix the class name, i.e. Pdo\Sqlite::EXPLAIN_MODE_* constants

return 0;
}
if (sqlite3_stmt_explain(S->stmt, (int)Z_LVAL_P(zval)) != SQLITE_OK) {
return 0;
}

return 1;
#if defined(__APPLE__)
} else {
zend_value_error("explain statement unsupported");
return 0;
}
#endif
#else
zend_value_error("explain statement unsupported");
return 0;
#endif
default:
return 0;
}

return 1;
}

const struct pdo_stmt_methods sqlite_stmt_methods = {
pdo_sqlite_stmt_dtor,
pdo_sqlite_stmt_execute,
pdo_sqlite_stmt_fetch,
pdo_sqlite_stmt_describe,
pdo_sqlite_stmt_get_col,
pdo_sqlite_stmt_param_hook,
NULL, /* set_attr */
pdo_sqlite_stmt_set_attribute, /* set_attr */
pdo_sqlite_stmt_get_attribute, /* get_attr */
pdo_sqlite_stmt_col_meta,
NULL, /* next_rowset */
Expand Down
Loading