/hphp/runtime/ext/ext_pdo.cpp
C++ | 3181 lines | 2844 code | 224 blank | 113 comment | 368 complexity | 90d855a73dd4ac677e3f5f928184c0dc MD5 | raw file
Possible License(s): LGPL-2.1, BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, MIT, LGPL-2.0, Apache-2.0
Large files files are truncated, but you can click here to view the full file
- /*
- +----------------------------------------------------------------------+
- | HipHop for PHP |
- +----------------------------------------------------------------------+
- | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
- | Copyright (c) 1997-2010 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- */
- #include "hphp/runtime/ext/ext_pdo.h"
- #include "hphp/runtime/ext/pdo_driver.h"
- #include "hphp/runtime/ext/pdo_mysql.h"
- #include "hphp/runtime/ext/ext_class.h"
- #include "hphp/runtime/ext/ext_function.h"
- #include "hphp/runtime/ext/ext_stream.h"
- #include "hphp/runtime/ext/ext_string.h"
- #include "hphp/runtime/base/class-info.h"
- #include "hphp/runtime/base/ini-setting.h"
- #include "hphp/runtime/base/string-buffer.h"
- #include "hphp/runtime/base/request-local.h"
- #include "hphp/runtime/base/macros.h"
- #include "hphp/system/systemlib.h"
- #define PDO_HANDLE_DBH_ERR(dbh) \
- if (strcmp(dbh->error_code, PDO_ERR_NONE)) { \
- pdo_handle_error(dbh, nullptr); \
- } \
- #define PDO_HANDLE_STMT_ERR(stmt) \
- if (strcmp(stmt->error_code, PDO_ERR_NONE)) { \
- pdo_handle_error(stmt->dbh, stmt); \
- } \
- namespace HPHP {
- IMPLEMENT_DEFAULT_EXTENSION(PDO);
- ///////////////////////////////////////////////////////////////////////////////
- // PDO constants
- const int64_t q_PDO$$PARAM_BOOL = PDO_PARAM_BOOL;
- const int64_t q_PDO$$PARAM_NULL = PDO_PARAM_NULL;
- const int64_t q_PDO$$PARAM_INT = PDO_PARAM_INT;
- const int64_t q_PDO$$PARAM_STR = PDO_PARAM_STR;
- const int64_t q_PDO$$PARAM_LOB = PDO_PARAM_LOB;
- const int64_t q_PDO$$PARAM_STMT = PDO_PARAM_STMT;
- const int64_t q_PDO$$PARAM_INPUT_OUTPUT = PDO_PARAM_INPUT_OUTPUT;
- const int64_t q_PDO$$PARAM_EVT_ALLOC = PDO_PARAM_EVT_ALLOC;
- const int64_t q_PDO$$PARAM_EVT_FREE = PDO_PARAM_EVT_FREE;
- const int64_t q_PDO$$PARAM_EVT_EXEC_PRE = PDO_PARAM_EVT_EXEC_PRE;
- const int64_t q_PDO$$PARAM_EVT_EXEC_POST = PDO_PARAM_EVT_EXEC_POST;
- const int64_t q_PDO$$PARAM_EVT_FETCH_PRE = PDO_PARAM_EVT_FETCH_PRE;
- const int64_t q_PDO$$PARAM_EVT_FETCH_POST = PDO_PARAM_EVT_FETCH_POST;
- const int64_t q_PDO$$PARAM_EVT_NORMALIZE = PDO_PARAM_EVT_NORMALIZE;
- const int64_t q_PDO$$FETCH_USE_DEFAULT = PDO_FETCH_USE_DEFAULT;
- const int64_t q_PDO$$FETCH_LAZY = PDO_FETCH_LAZY;
- const int64_t q_PDO$$FETCH_ASSOC = PDO_FETCH_ASSOC;
- const int64_t q_PDO$$FETCH_NUM = PDO_FETCH_NUM;
- const int64_t q_PDO$$FETCH_BOTH = PDO_FETCH_BOTH;
- const int64_t q_PDO$$FETCH_OBJ = PDO_FETCH_OBJ;
- const int64_t q_PDO$$FETCH_BOUND = PDO_FETCH_BOUND;
- const int64_t q_PDO$$FETCH_COLUMN = PDO_FETCH_COLUMN;
- const int64_t q_PDO$$FETCH_CLASS = PDO_FETCH_CLASS;
- const int64_t q_PDO$$FETCH_INTO = PDO_FETCH_INTO;
- const int64_t q_PDO$$FETCH_FUNC = PDO_FETCH_FUNC;
- const int64_t q_PDO$$FETCH_GROUP = PDO_FETCH_GROUP;
- const int64_t q_PDO$$FETCH_UNIQUE = PDO_FETCH_UNIQUE;
- const int64_t q_PDO$$FETCH_KEY_PAIR = PDO_FETCH_KEY_PAIR;
- const int64_t q_PDO$$FETCH_CLASSTYPE = PDO_FETCH_CLASSTYPE;
- const int64_t q_PDO$$FETCH_SERIALIZE = PDO_FETCH_SERIALIZE;
- const int64_t q_PDO$$FETCH_PROPS_LATE = PDO_FETCH_PROPS_LATE;
- const int64_t q_PDO$$FETCH_NAMED = PDO_FETCH_NAMED;
- const int64_t q_PDO$$ATTR_AUTOCOMMIT = PDO_ATTR_AUTOCOMMIT;
- const int64_t q_PDO$$ATTR_PREFETCH = PDO_ATTR_PREFETCH;
- const int64_t q_PDO$$ATTR_TIMEOUT = PDO_ATTR_TIMEOUT;
- const int64_t q_PDO$$ATTR_ERRMODE = PDO_ATTR_ERRMODE;
- const int64_t q_PDO$$ATTR_SERVER_VERSION = PDO_ATTR_SERVER_VERSION;
- const int64_t q_PDO$$ATTR_CLIENT_VERSION = PDO_ATTR_CLIENT_VERSION;
- const int64_t q_PDO$$ATTR_SERVER_INFO = PDO_ATTR_SERVER_INFO;
- const int64_t q_PDO$$ATTR_CONNECTION_STATUS = PDO_ATTR_CONNECTION_STATUS;
- const int64_t q_PDO$$ATTR_CASE = PDO_ATTR_CASE;
- const int64_t q_PDO$$ATTR_CURSOR_NAME = PDO_ATTR_CURSOR_NAME;
- const int64_t q_PDO$$ATTR_CURSOR = PDO_ATTR_CURSOR;
- const int64_t q_PDO$$ATTR_ORACLE_NULLS = PDO_ATTR_ORACLE_NULLS;
- const int64_t q_PDO$$ATTR_PERSISTENT = PDO_ATTR_PERSISTENT;
- const int64_t q_PDO$$ATTR_STATEMENT_CLASS = PDO_ATTR_STATEMENT_CLASS;
- const int64_t q_PDO$$ATTR_FETCH_TABLE_NAMES = PDO_ATTR_FETCH_TABLE_NAMES;
- const int64_t q_PDO$$ATTR_FETCH_CATALOG_NAMES = PDO_ATTR_FETCH_CATALOG_NAMES;
- const int64_t q_PDO$$ATTR_DRIVER_NAME = PDO_ATTR_DRIVER_NAME;
- const int64_t q_PDO$$ATTR_STRINGIFY_FETCHES = PDO_ATTR_STRINGIFY_FETCHES;
- const int64_t q_PDO$$ATTR_MAX_COLUMN_LEN = PDO_ATTR_MAX_COLUMN_LEN;
- const int64_t q_PDO$$ATTR_EMULATE_PREPARES = PDO_ATTR_EMULATE_PREPARES;
- const int64_t q_PDO$$ATTR_DEFAULT_FETCH_MODE = PDO_ATTR_DEFAULT_FETCH_MODE;
- const int64_t q_PDO$$ERRMODE_SILENT = PDO_ERRMODE_SILENT;
- const int64_t q_PDO$$ERRMODE_WARNING = PDO_ERRMODE_WARNING;
- const int64_t q_PDO$$ERRMODE_EXCEPTION = PDO_ERRMODE_EXCEPTION;
- const int64_t q_PDO$$CASE_NATURAL = PDO_CASE_NATURAL;
- const int64_t q_PDO$$CASE_LOWER = PDO_CASE_LOWER;
- const int64_t q_PDO$$CASE_UPPER = PDO_CASE_UPPER;
- const int64_t q_PDO$$NULL_NATURAL = PDO_NULL_NATURAL;
- const int64_t q_PDO$$NULL_EMPTY_STRING = PDO_NULL_EMPTY_STRING;
- const int64_t q_PDO$$NULL_TO_STRING = PDO_NULL_TO_STRING;
- const StaticString q_PDO$$ERR_NONE(LITSTR_INIT(PDO_ERR_NONE));
- const int64_t q_PDO$$FETCH_ORI_NEXT = PDO_FETCH_ORI_NEXT;
- const int64_t q_PDO$$FETCH_ORI_PRIOR = PDO_FETCH_ORI_PRIOR;
- const int64_t q_PDO$$FETCH_ORI_FIRST = PDO_FETCH_ORI_FIRST;
- const int64_t q_PDO$$FETCH_ORI_LAST = PDO_FETCH_ORI_LAST;
- const int64_t q_PDO$$FETCH_ORI_ABS = PDO_FETCH_ORI_ABS;
- const int64_t q_PDO$$FETCH_ORI_REL = PDO_FETCH_ORI_REL;
- const int64_t q_PDO$$CURSOR_FWDONLY = PDO_CURSOR_FWDONLY;
- const int64_t q_PDO$$CURSOR_SCROLL = PDO_CURSOR_SCROLL;
- ///////////////////////////////////////////////////////////////////////////////
- const int64_t q_PDO$$MYSQL_ATTR_USE_BUFFERED_QUERY =
- PDO_MYSQL_ATTR_USE_BUFFERED_QUERY;
- const int64_t q_PDO$$MYSQL_ATTR_LOCAL_INFILE = PDO_MYSQL_ATTR_LOCAL_INFILE;
- const int64_t q_PDO$$MYSQL_ATTR_MAX_BUFFER_SIZE =
- PDO_MYSQL_ATTR_MAX_BUFFER_SIZE;
- const int64_t q_PDO$$MYSQL_ATTR_INIT_COMMAND = PDO_MYSQL_ATTR_INIT_COMMAND;
- const int64_t q_PDO$$MYSQL_ATTR_READ_DEFAULT_FILE =
- PDO_MYSQL_ATTR_READ_DEFAULT_FILE;
- const int64_t q_PDO$$MYSQL_ATTR_READ_DEFAULT_GROUP =
- PDO_MYSQL_ATTR_READ_DEFAULT_GROUP;
- const int64_t q_PDO$$MYSQL_ATTR_COMPRESS = PDO_MYSQL_ATTR_COMPRESS;
- const int64_t q_PDO$$MYSQL_ATTR_DIRECT_QUERY = PDO_MYSQL_ATTR_DIRECT_QUERY;
- const int64_t q_PDO$$MYSQL_ATTR_FOUND_ROWS = PDO_MYSQL_ATTR_FOUND_ROWS;
- const int64_t q_PDO$$MYSQL_ATTR_IGNORE_SPACE = PDO_MYSQL_ATTR_IGNORE_SPACE;
- ///////////////////////////////////////////////////////////////////////////////
- // extension functions
- Array f_pdo_drivers() {
- Array ret = Array::Create();
- const PDODriverMap &drivers = PDODriver::GetDrivers();
- for (PDODriverMap::const_iterator iter = drivers.begin();
- iter != drivers.end(); ++iter) {
- ret.append(iter->second->getName());
- }
- return ret;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // error handling
- struct pdo_sqlstate_info {
- const char *state;
- const char *desc;
- };
- static const struct pdo_sqlstate_info err_initializer[] = {
- { "00000", "No error" },
- { "01000", "Warning" },
- { "01001", "Cursor operation conflict" },
- { "01002", "Disconnect error" },
- { "01003", "NULL value eliminated in set function" },
- { "01004", "String data, right truncated" },
- { "01006", "Privilege not revoked" },
- { "01007", "Privilege not granted" },
- { "01008", "Implicit zero bit padding" },
- { "0100C", "Dynamic result sets returned" },
- { "01P01", "Deprecated feature" },
- { "01S00", "Invalid connection string attribute" },
- { "01S01", "Error in row" },
- { "01S02", "Option value changed" },
- { "01S06",
- "Attempt to fetch before the result set returned the first rowset" },
- { "01S07", "Fractional truncation" },
- { "01S08", "Error saving File DSN" },
- { "01S09", "Invalid keyword" },
- { "02000", "No data" },
- { "02001", "No additional dynamic result sets returned" },
- { "03000", "Sql statement not yet complete" },
- { "07002", "COUNT field incorrect" },
- { "07005", "Prepared statement not a cursor-specification" },
- { "07006", "Restricted data type attribute violation" },
- { "07009", "Invalid descriptor index" },
- { "07S01", "Invalid use of default parameter" },
- { "08000", "Connection exception" },
- { "08001", "Client unable to establish connection" },
- { "08002", "Connection name in use" },
- { "08003", "Connection does not exist" },
- { "08004", "Server rejected the connection" },
- { "08006", "Connection failure" },
- { "08007", "Connection failure during transaction" },
- { "08S01", "Communication link failure" },
- { "09000", "Triggered action exception" },
- { "0A000", "Feature not supported" },
- { "0B000", "Invalid transaction initiation" },
- { "0F000", "Locator exception" },
- { "0F001", "Invalid locator specification" },
- { "0L000", "Invalid grantor" },
- { "0LP01", "Invalid grant operation" },
- { "0P000", "Invalid role specification" },
- { "21000", "Cardinality violation" },
- { "21S01", "Insert value list does not match column list" },
- { "21S02", "Degree of derived table does not match column list" },
- { "22000", "Data exception" },
- { "22001", "String data, right truncated" },
- { "22002", "Indicator variable required but not supplied" },
- { "22003", "Numeric value out of range" },
- { "22004", "Null value not allowed" },
- { "22005", "Error in assignment" },
- { "22007", "Invalid datetime format" },
- { "22008", "Datetime field overflow" },
- { "22009", "Invalid time zone displacement value" },
- { "2200B", "Escape character conflict" },
- { "2200C", "Invalid use of escape character" },
- { "2200D", "Invalid escape octet" },
- { "2200F", "Zero length character string" },
- { "2200G", "Most specific type mismatch" },
- { "22010", "Invalid indicator parameter value" },
- { "22011", "Substring error" },
- { "22012", "Division by zero" },
- { "22015", "Interval field overflow" },
- { "22018", "Invalid character value for cast specification" },
- { "22019", "Invalid escape character" },
- { "2201B", "Invalid regular expression" },
- { "2201E", "Invalid argument for logarithm" },
- { "2201F", "Invalid argument for power function" },
- { "2201G", "Invalid argument for width bucket function" },
- { "22020", "Invalid limit value" },
- { "22021", "Character not in repertoire" },
- { "22022", "Indicator overflow" },
- { "22023", "Invalid parameter value" },
- { "22024", "Unterminated c string" },
- { "22025", "Invalid escape sequence" },
- { "22026", "String data, length mismatch" },
- { "22027", "Trim error" },
- { "2202E", "Array subscript error" },
- { "22P01", "Floating point exception" },
- { "22P02", "Invalid text representation" },
- { "22P03", "Invalid binary representation" },
- { "22P04", "Bad copy file format" },
- { "22P05", "Untranslatable character" },
- { "23000", "Integrity constraint violation" },
- { "23001", "Restrict violation" },
- { "23502", "Not null violation" },
- { "23503", "Foreign key violation" },
- { "23505", "Unique violation" },
- { "23514", "Check violation" },
- { "24000", "Invalid cursor state" },
- { "25000", "Invalid transaction state" },
- { "25001", "Active sql transaction" },
- { "25002", "Branch transaction already active" },
- { "25003", "Inappropriate access mode for branch transaction" },
- { "25004", "Inappropriate isolation level for branch transaction" },
- { "25005", "No active sql transaction for branch transaction" },
- { "25006", "Read only sql transaction" },
- { "25007", "Schema and data statement mixing not supported" },
- { "25008", "Held cursor requires same isolation level" },
- { "25P01", "No active sql transaction" },
- { "25P02", "In failed sql transaction" },
- { "25S01", "Transaction state" },
- { "25S02", "Transaction is still active" },
- { "25S03", "Transaction is rolled back" },
- { "26000", "Invalid sql statement name" },
- { "27000", "Triggered data change violation" },
- { "28000", "Invalid authorization specification" },
- { "2B000", "Dependent privilege descriptors still exist" },
- { "2BP01", "Dependent objects still exist" },
- { "2D000", "Invalid transaction termination" },
- { "2F000", "Sql routine exception" },
- { "2F002", "Modifying sql data not permitted" },
- { "2F003", "Prohibited sql statement attempted" },
- { "2F004", "Reading sql data not permitted" },
- { "2F005", "Function executed no return statement" },
- { "34000", "Invalid cursor name" },
- { "38000", "External routine exception" },
- { "38001", "Containing sql not permitted" },
- { "38002", "Modifying sql data not permitted" },
- { "38003", "Prohibited sql statement attempted" },
- { "38004", "Reading sql data not permitted" },
- { "39000", "External routine invocation exception" },
- { "39001", "Invalid sqlstate returned" },
- { "39004", "Null value not allowed" },
- { "39P01", "Trigger protocol violated" },
- { "39P02", "Srf protocol violated" },
- { "3B000", "Savepoint exception" },
- { "3B001", "Invalid savepoint specification" },
- { "3C000", "Duplicate cursor name" },
- { "3D000", "Invalid catalog name" },
- { "3F000", "Invalid schema name" },
- { "40000", "Transaction rollback" },
- { "40001", "Serialization failure" },
- { "40002", "Transaction integrity constraint violation" },
- { "40003", "Statement completion unknown" },
- { "40P01", "Deadlock detected" },
- { "42000", "Syntax error or access violation" },
- { "42501", "Insufficient privilege" },
- { "42601", "Syntax error" },
- { "42602", "Invalid name" },
- { "42611", "Invalid column definition" },
- { "42622", "Name too long" },
- { "42701", "Duplicate column" },
- { "42702", "Ambiguous column" },
- { "42703", "Undefined column" },
- { "42704", "Undefined object" },
- { "42710", "Duplicate object" },
- { "42712", "Duplicate alias" },
- { "42723", "Duplicate function" },
- { "42725", "Ambiguous function" },
- { "42803", "Grouping error" },
- { "42804", "Datatype mismatch" },
- { "42809", "Wrong object type" },
- { "42830", "Invalid foreign key" },
- { "42846", "Cannot coerce" },
- { "42883", "Undefined function" },
- { "42939", "Reserved name" },
- { "42P01", "Undefined table" },
- { "42P02", "Undefined parameter" },
- { "42P03", "Duplicate cursor" },
- { "42P04", "Duplicate database" },
- { "42P05", "Duplicate prepared statement" },
- { "42P06", "Duplicate schema" },
- { "42P07", "Duplicate table" },
- { "42P08", "Ambiguous parameter" },
- { "42P09", "Ambiguous alias" },
- { "42P10", "Invalid column reference" },
- { "42P11", "Invalid cursor definition" },
- { "42P12", "Invalid database definition" },
- { "42P13", "Invalid function definition" },
- { "42P14", "Invalid prepared statement definition" },
- { "42P15", "Invalid schema definition" },
- { "42P16", "Invalid table definition" },
- { "42P17", "Invalid object definition" },
- { "42P18", "Indeterminate datatype" },
- { "42S01", "Base table or view already exists" },
- { "42S02", "Base table or view not found" },
- { "42S11", "Index already exists" },
- { "42S12", "Index not found" },
- { "42S21", "Column already exists" },
- { "42S22", "Column not found" },
- { "44000", "WITH CHECK OPTION violation" },
- { "53000", "Insufficient resources" },
- { "53100", "Disk full" },
- { "53200", "Out of memory" },
- { "53300", "Too many connections" },
- { "54000", "Program limit exceeded" },
- { "54001", "Statement too complex" },
- { "54011", "Too many columns" },
- { "54023", "Too many arguments" },
- { "55000", "Object not in prerequisite state" },
- { "55006", "Object in use" },
- { "55P02", "Cant change runtime param" },
- { "55P03", "Lock not available" },
- { "57000", "Operator intervention" },
- { "57014", "Query canceled" },
- { "57P01", "Admin shutdown" },
- { "57P02", "Crash shutdown" },
- { "57P03", "Cannot connect now" },
- { "58030", "Io error" },
- { "58P01", "Undefined file" },
- { "58P02", "Duplicate file" },
- { "F0000", "Config file error" },
- { "F0001", "Lock file exists" },
- { "HY000", "General error" },
- { "HY001", "Memory allocation error" },
- { "HY003", "Invalid application buffer type" },
- { "HY004", "Invalid SQL data type" },
- { "HY007", "Associated statement is not prepared" },
- { "HY008", "Operation canceled" },
- { "HY009", "Invalid use of null pointer" },
- { "HY010", "Function sequence error" },
- { "HY011", "Attribute cannot be set now" },
- { "HY012", "Invalid transaction operation code" },
- { "HY013", "Memory management error" },
- { "HY014", "Limit on the number of handles exceeded" },
- { "HY015", "No cursor name available" },
- { "HY016", "Cannot modify an implementation row descriptor" },
- { "HY017", "Invalid use of an automatically allocated descriptor handle" },
- { "HY018", "Server declined cancel request" },
- { "HY019", "Non-character and non-binary data sent in pieces" },
- { "HY020", "Attempt to concatenate a null value" },
- { "HY021", "Inconsistent descriptor information" },
- { "HY024", "Invalid attribute value" },
- { "HY090", "Invalid string or buffer length" },
- { "HY091", "Invalid descriptor field identifier" },
- { "HY092", "Invalid attribute/option identifier" },
- { "HY093", "Invalid parameter number" },
- { "HY095", "Function type out of range" },
- { "HY096", "Invalid information type" },
- { "HY097", "Column type out of range" },
- { "HY098", "Scope type out of range" },
- { "HY099", "Nullable type out of range" },
- { "HY100", "Uniqueness option type out of range" },
- { "HY101", "Accuracy option type out of range" },
- { "HY103", "Invalid retrieval code" },
- { "HY104", "Invalid precision or scale value" },
- { "HY105", "Invalid parameter type" },
- { "HY106", "Fetch type out of range" },
- { "HY107", "Row value out of range" },
- { "HY109", "Invalid cursor position" },
- { "HY110", "Invalid driver completion" },
- { "HY111", "Invalid bookmark value" },
- { "HYC00", "Optional feature not implemented" },
- { "HYT00", "Timeout expired" },
- { "HYT01", "Connection timeout expired" },
- { "IM001", "Driver does not support this function" },
- { "IM002", "Data source name not found and no default driver specified" },
- { "IM003", "Specified driver could not be loaded" },
- { "IM004", "Driver's SQLAllocHandle on SQL_HANDLE_ENV failed" },
- { "IM005", "Driver's SQLAllocHandle on SQL_HANDLE_DBC failed" },
- { "IM006", "Driver's SQLSetConnectAttr failed" },
- { "IM007", "No data source or driver specified; dialog prohibited" },
- { "IM008", "Dialog failed" },
- { "IM009", "Unable to load translation DLL" },
- { "IM010", "Data source name too long" },
- { "IM011", "Driver name too long" },
- { "IM012", "DRIVER keyword syntax error" },
- { "IM013", "Trace file error" },
- { "IM014", "Invalid name of File DSN" },
- { "IM015", "Corrupt file data source" },
- { "P0000", "Plpgsql error" },
- { "P0001", "Raise exception" },
- { "XX000", "Internal error" },
- { "XX001", "Data corrupted" },
- { "XX002", "Index corrupted" }
- };
- class PDOErrorHash : private hphp_const_char_map<const char *> {
- public:
- PDOErrorHash() {
- for (unsigned int i = 0;
- i < sizeof(err_initializer)/sizeof(err_initializer[0]); i++) {
- const struct pdo_sqlstate_info *info = &err_initializer[i];
- (*this)[info->state] = info->desc;
- }
- }
- const char *description(const char *state) {
- const_iterator iter = find(state);
- if (iter != end()) {
- return iter->second;
- }
- return "<<Unknown error>>";
- }
- };
- static PDOErrorHash s_err_hash;
- const StaticString
- s_code("code"),
- s_message("message"),
- s_errorInfo("errorInfo"),
- s_PDOException("PDOException");
- void throw_pdo_exception(CVarRef code, CVarRef info, const char *fmt, ...) {
- ObjectData *obj = SystemLib::AllocPDOExceptionObject();
- obj->o_set(s_code, code, s_PDOException);
- va_list ap;
- va_start(ap, fmt);
- string msg;
- Util::string_vsnprintf(msg, fmt, ap);
- obj->o_set(s_message, String(msg), s_PDOException);
- va_end(ap);
- if (!info.isNull()) {
- obj->o_set(s_errorInfo, info, s_PDOException);
- }
- throw Object(obj);
- }
- void pdo_raise_impl_error(sp_PDOConnection dbh, sp_PDOStatement stmt,
- const char *sqlstate, const char *supp) {
- PDOErrorType *pdo_err = &dbh->error_code;
- if (stmt.get()) {
- pdo_err = &stmt->error_code;
- }
- strcpy(*pdo_err, sqlstate);
- const char *msg = s_err_hash.description(sqlstate);
- string err = "SQLSTATE["; err += sqlstate; err += "]: "; err += msg;
- if (supp) {
- err += ": "; err += supp;
- }
- if (dbh->error_mode != PDO_ERRMODE_EXCEPTION) {
- raise_warning("%s", err.c_str());
- } else {
- Array info;
- info.append(String(*pdo_err, CopyString));
- info.append(0LL);
- throw_pdo_exception(String(sqlstate, CopyString), info, "%s", err.c_str());
- }
- }
- static void pdo_handle_error(sp_PDOConnection dbh, sp_PDOStatement stmt) {
- if (dbh->error_mode == PDO_ERRMODE_SILENT) {
- return;
- }
- PDOErrorType *pdo_err = &dbh->error_code;
- if (stmt.get()) {
- pdo_err = &stmt->error_code;
- }
- /* hash sqlstate to error messages */
- const char *msg = s_err_hash.description(*pdo_err);
- int64_t native_code = 0;
- String supp;
- Array info;
- if (dbh->support(PDOConnection::MethodFetchErr)) {
- info = Array::Create();
- info.append(String(*pdo_err, CopyString));
- if (dbh->fetchErr(stmt.get(), info)) {
- if (info.exists(1)) {
- native_code = info[1].toInt64();
- }
- if (info.exists(2)) {
- supp = info[2].toString();
- }
- }
- }
- string err = "SQLSTATE["; err += *pdo_err; err += "]: "; err += msg;
- if (!supp.empty()) {
- err += ": "; err += String(native_code).data();
- err += " "; err += supp.data();
- }
- if (dbh->error_mode != PDO_ERRMODE_EXCEPTION) {
- raise_warning("%s", err.c_str());
- } else {
- throw_pdo_exception(String(*pdo_err, CopyString), info, "%s", err.c_str());
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // helpers for PDO class
- static inline int64_t pdo_attr_lval(CArrRef options, PDOAttributeType name,
- int64_t defval) {
- if (options.exists(name)) {
- return options[name].toInt64();
- }
- return defval;
- }
- static inline String pdo_attr_strval(CArrRef options, PDOAttributeType name,
- const String& defval) {
- if (options.exists(name)) {
- return options[name].toString();
- }
- return defval;
- }
- static Object pdo_stmt_instantiate(sp_PDOConnection dbh, const String& clsname,
- CVarRef ctor_args) {
- String name = clsname;
- if (name.empty()) {
- name = "PDOStatement";
- }
- if (!ctor_args.isNull() && !ctor_args.isArray()) {
- pdo_raise_impl_error(dbh, nullptr, "HY000",
- "constructor arguments must be passed as an array");
- return Object();
- }
- Class* cls = Unit::loadClass(name.get());
- if (!cls) {
- return Object();
- }
- return ObjectData::newInstance(cls);
- }
- static void pdo_stmt_construct(sp_PDOStatement stmt, Object object,
- const String& clsname, CVarRef ctor_args) {
- if (clsname.empty()) {
- return;
- }
- Class* cls = Unit::loadClass(clsname.get());
- if (!cls) {
- return;
- }
- object->o_set("queryString", stmt->query_string);
- TypedValue ret;
- ObjectData* inst = object.get();
- g_vmContext->invokeFunc(&ret, cls->getCtor(), ctor_args.toArray(), inst);
- tvRefcountedDecRef(&ret);
- }
- static bool valid_statement_class(sp_PDOConnection dbh, CVarRef opt,
- String &clsname, Variant &ctor_args) {
- if (!opt.isArray() || !opt.toArray().exists(0) || !opt[0].isString() ||
- !f_class_exists(opt[0].toString())) {
- pdo_raise_impl_error
- (dbh, nullptr, "HY000",
- "PDO::ATTR_STATEMENT_CLASS requires format array(classname, "
- "array(ctor_args)); the classname must be a string specifying "
- "an existing class");
- PDO_HANDLE_DBH_ERR(dbh);
- return false;
- }
- clsname = opt[0].toString();
- if (!f_is_subclass_of(clsname, "PDOStatement")) {
- pdo_raise_impl_error
- (dbh, nullptr, "HY000",
- "user-supplied statement class must be derived from PDOStatement");
- PDO_HANDLE_DBH_ERR(dbh);
- return false;
- }
- HPHP::Class* cls = HPHP::Unit::loadClass(clsname.get());
- if (cls) {
- const HPHP::Func* method = cls->getDeclaredCtor();
- if (method && method->isPublic()) {
- pdo_raise_impl_error
- (dbh, nullptr, "HY000",
- "user-supplied statement class cannot have a public constructor");
- PDO_HANDLE_DBH_ERR(dbh);
- return false;
- }
- }
- if (opt.toArray().exists(1)) {
- Variant item = opt[1];
- if (!item.isArray()) {
- pdo_raise_impl_error
- (dbh, nullptr, "HY000",
- "PDO::ATTR_STATEMENT_CLASS requires format array(classname, "
- "ctor_args); ctor_args must be an array");
- PDO_HANDLE_DBH_ERR(dbh);
- return false;
- }
- ctor_args = item;
- }
- return true;
- }
- static bool pdo_stmt_describe_columns(sp_PDOStatement stmt) {
- for (int col = 0; col < stmt->column_count; col++) {
- if (!stmt->describer(col)) {
- return false;
- }
- String &name = stmt->columns[col].toResource().getTyped<PDOColumn>()->name;
- /* if we are applying case conversions on column names, do so now */
- if (stmt->dbh->native_case != stmt->dbh->desired_case &&
- stmt->dbh->desired_case != PDO_CASE_NATURAL) {
- switch (stmt->dbh->desired_case) {
- case PDO_CASE_UPPER:
- name = f_strtoupper(name);
- break;
- case PDO_CASE_LOWER:
- name = f_strtolower(name);
- break;
- default:;
- }
- }
- if (stmt->bound_columns.exists(name)) {
- PDOBoundParam *param =
- stmt->bound_columns[name].toResource().getTyped<PDOBoundParam>();
- param->paramno = col;
- }
- }
- return true;
- }
- static bool pdo_stmt_verify_mode(sp_PDOStatement stmt, int64_t mode,
- bool fetch_all) {
- int flags = mode & PDO_FETCH_FLAGS;
- mode = mode & ~PDO_FETCH_FLAGS;
- if (mode < 0 || mode > PDO_FETCH__MAX) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode");
- return false;
- }
- if (mode == PDO_FETCH_USE_DEFAULT) {
- flags = stmt->default_fetch_type & PDO_FETCH_FLAGS;
- mode = stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
- }
- switch (mode) {
- case PDO_FETCH_FUNC:
- if (!fetch_all) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "PDO::FETCH_FUNC is only allowed in "
- "PDOStatement::fetchAll()");
- return false;
- }
- return true;
- case PDO_FETCH_LAZY:
- if (fetch_all) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "PDO::FETCH_LAZY can't be used with "
- "PDOStatement::fetchAll()");
- return false;
- }
- default:
- if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "PDO::FETCH_SERIALIZE can only be used "
- "together with PDO::FETCH_CLASS");
- return false;
- }
- if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "PDO::FETCH_CLASSTYPE can only be used "
- "together with PDO::FETCH_CLASS");
- return false;
- }
- if (mode >= PDO_FETCH__MAX) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode");
- return false;
- }
- /* no break; */
- case PDO_FETCH_CLASS:
- break;
- }
- return true;
- }
- static bool do_fetch_class_prepare(sp_PDOStatement stmt) {
- String clsname = stmt->fetch.clsname;
- if (clsname.empty()) {
- stmt->fetch.clsname = "stdclass";
- }
- stmt->fetch.constructor = empty_string; //NULL;
- HPHP::Class* cls = HPHP::Unit::loadClass(clsname.get());
- if (cls) {
- const HPHP::Func* method = cls->getDeclaredCtor();
- if (method) {
- stmt->fetch.constructor = method->nameRef();
- return true;
- }
- }
- if (!stmt->fetch.ctor_args.isNull()) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "user-supplied class does not have a constructor, "
- "use NULL for the ctor_params parameter, or simply "
- "omit it");
- return false;
- }
- return true; /* no ctor no args is also ok */
- }
- static bool pdo_stmt_set_fetch_mode(sp_PDOStatement stmt, int _argc, int64_t mode,
- CArrRef _argv) {
- _argc = _argv.size() + 1;
- if (stmt->default_fetch_type == PDO_FETCH_INTO) {
- stmt->fetch.into.reset();
- }
- stmt->default_fetch_type = PDO_FETCH_BOTH;
- if (!pdo_stmt_verify_mode(stmt, mode, false)) {
- strcpy(stmt->error_code, PDO_ERR_NONE);
- return false;
- }
- int flags = mode & PDO_FETCH_FLAGS;
- bool retval = false;
- switch (mode & ~PDO_FETCH_FLAGS) {
- case PDO_FETCH_USE_DEFAULT:
- case PDO_FETCH_LAZY:
- case PDO_FETCH_ASSOC:
- case PDO_FETCH_NUM:
- case PDO_FETCH_BOTH:
- case PDO_FETCH_OBJ:
- case PDO_FETCH_BOUND:
- case PDO_FETCH_NAMED:
- case PDO_FETCH_KEY_PAIR:
- if (_argc != 1) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "fetch mode doesn't allow any extra arguments");
- } else {
- retval = true;
- }
- break;
- case PDO_FETCH_COLUMN:
- if (_argc != 2) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "fetch mode requires the colno argument");
- } else if (!_argv[0].isInteger()) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "colno must be an integer");
- } else {
- stmt->fetch.column = _argv[0].toInt64();
- retval = true;
- }
- break;
- case PDO_FETCH_CLASS:
- /* Gets its class name from 1st column */
- if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
- if (_argc != 1) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "fetch mode doesn't allow any extra arguments");
- } else {
- stmt->fetch.clsname.clear();
- retval = true;
- }
- } else {
- if (_argc < 2) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "fetch mode requires the classname argument");
- } else if (_argc > 3) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "too many arguments");
- } else if (!_argv[0].isString()) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "classname must be a string");
- } else {
- retval = f_class_exists(_argv[0].toString());
- if (retval) {
- stmt->fetch.clsname = _argv[0].toString();
- }
- }
- }
- if (retval) {
- stmt->fetch.ctor_args.reset();
- if (_argc == 3) {
- if (!_argv[1].isNull() && !_argv[1].isArray()) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "ctor_args must be either NULL or an array");
- retval = false;
- } else {
- stmt->fetch.ctor_args = _argv[1];
- }
- }
- if (retval) {
- do_fetch_class_prepare(stmt);
- }
- }
- break;
- case PDO_FETCH_INTO:
- if (_argc != 2) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "fetch mode requires the object parameter");
- } else if (!_argv[0].isObject()) {
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000",
- "object must be an object");
- } else {
- retval = true;
- }
- if (retval) {
- stmt->fetch.into = _argv[0];
- }
- break;
- default:
- pdo_raise_impl_error(stmt->dbh, stmt, "22003",
- "Invalid fetch mode specified");
- }
- if (retval) {
- stmt->default_fetch_type = (PDOFetchType)mode;
- }
- /*
- * PDO error (if any) has already been raised at this point.
- *
- * The error_code is cleared, otherwise the caller will read the
- * last error message from the driver.
- *
- */
- strcpy(stmt->error_code, PDO_ERR_NONE);
- return retval;
- }
- ///////////////////////////////////////////////////////////////////////////////
- class PDORequestData : public RequestEventHandler {
- public:
- virtual void requestInit() {
- }
- virtual void requestShutdown() {
- for (std::set<PDOConnection*>::iterator iter =
- m_persistent_connections.begin();
- iter != m_persistent_connections.end(); ++iter) {
- PDOConnection *conn = *iter;
- if (!conn) {
- // Dead handle in the set
- continue;
- }
- if (conn->support(PDOConnection::MethodCheckLiveness) &&
- !conn->checkLiveness()) {
- // Dead connection in the handle
- continue;
- }
- // All seems right, save it
- conn->persistentSave();
- }
- }
- public:
- std::set<PDOConnection*> m_persistent_connections;
- };
- IMPLEMENT_STATIC_REQUEST_LOCAL(PDORequestData, s_pdo_request_data);
- ///////////////////////////////////////////////////////////////////////////////
- // PDO
- c_PDO::c_PDO(Class* cb) : ExtObjectData(cb) {
- }
- c_PDO::~c_PDO() {
- }
- void c_PDO::sweep() {
- // PDOConnection is not sweepable, so clean it up manually.
- static_assert(!std::is_base_of<Sweepable, PDOConnection>::value,
- "Remove the call to reset() below.");
- m_dbh.reset();
- }
- void c_PDO::t___construct(const String& dsn, const String& username /* = null_string */,
- const String& password /* = null_string */,
- CArrRef options /* = null_array */) {
- String data_source = dsn;
- /* parse the data source name */
- const char *colon = strchr(data_source.data(), ':');
- if (!colon) {
- /* let's see if this string has a matching dsn in the php.ini */
- String name = "pdo.dsn."; name += data_source;
- String ini_dsn;
- if (!IniSetting::Get(name, ini_dsn)) {
- throw_pdo_exception(uninit_null(), uninit_null(), "invalid data source name");
- }
- data_source = ini_dsn;
- colon = strchr(data_source.data(), ':');
- if (!colon) {
- throw_pdo_exception(uninit_null(), uninit_null(), "invalid data source name (via INI: %s)",
- ini_dsn.data());
- }
- }
- if (!strncmp(data_source.data(), "uri:", 4)) {
- /* the specified URI holds connection details */
- Variant stream = File::Open(data_source.substr(4), "rb");
- if (same(stream, false)) {
- throw_pdo_exception(uninit_null(), uninit_null(), "invalid data source URI");
- }
- data_source = stream.toResource().getTyped<File>()->readLine(1024);
- colon = strchr(data_source.data(), ':');
- if (!colon) {
- throw_pdo_exception(uninit_null(), uninit_null(), "invalid data source name (via URI)");
- }
- }
- const PDODriverMap &drivers = PDODriver::GetDrivers();
- String name = data_source.substr(0, colon - data_source.data());
- PDODriverMap::const_iterator iter = drivers.find(name.data());
- if (iter == drivers.end()) {
- /* NB: don't want to include the data_source in the error message as
- * it might contain a password */
- throw_pdo_exception(uninit_null(), uninit_null(), "could not find driver");
- }
- PDODriver *driver = iter->second;
- /* is this supposed to be a persistent connection ? */
- bool is_persistent = false;
- bool call_factory = true;
- String shashkey;
- if (!options.empty()) {
- StringBuffer hashkey;
- if (options.exists(PDO_ATTR_PERSISTENT)) {
- Variant v = options[PDO_ATTR_PERSISTENT];
- String sv = v.toString();
- if (v.isString() && !sv.isNumeric() && !sv.empty()) {
- /* user specified key */
- hashkey.printf("PDO:DBH:DSN=%s:%s:%s:%s",
- data_source.data(), username.data(),
- password.data(), sv.data());
- is_persistent = true;
- } else {
- is_persistent = v.toInt64();
- hashkey.printf("PDO:DBH:DSN=%s:%s:%s",
- data_source.data(), username.data(),
- password.data());
- }
- }
- if (is_persistent) {
- shashkey = hashkey.detach();
- /* let's see if we have one cached.... */
- m_dbh = dynamic_cast<PDOConnection*>
- (g_persistentObjects->get(PDOConnection::PersistentKey,
- shashkey.data()));
- if (m_dbh.get()) {
- m_dbh->persistentRestore();
- /* is the connection still alive ? */
- if (m_dbh->support(PDOConnection::MethodCheckLiveness) &&
- !m_dbh->checkLiveness()) {
- /* nope... need to kill it */
- s_pdo_request_data->m_persistent_connections.erase(m_dbh.get());
- m_dbh = nullptr;
- } else {
- /* Yep, use it and mark it for saving at rshutdown */
- s_pdo_request_data->m_persistent_connections.insert(m_dbh.get());
- }
- }
- if (m_dbh.get()) {
- call_factory = false;
- } else {
- /* need a brand new pdbh */
- m_dbh = driver->createConnection(colon+1, username, password, options);
- if (m_dbh.get() == nullptr) {
- throw_pdo_exception(uninit_null(), uninit_null(), "unable to create a connection");
- }
- m_dbh->persistent_id = string(shashkey.data(), shashkey.size());
- }
- }
- }
- if (!m_dbh.get()) {
- m_dbh = driver->createConnection(colon+1, username, password, options);
- if (m_dbh.get() == nullptr) {
- throw_pdo_exception(uninit_null(), uninit_null(), "unable to create a connection");
- }
- }
- if (call_factory) {
- m_dbh->default_fetch_type = PDO_FETCH_BOTH;
- }
- m_dbh->auto_commit = pdo_attr_lval(options, PDO_ATTR_AUTOCOMMIT, 1);
- if (!call_factory) {
- /* we got a persistent guy from our cache */
- for (ArrayIter iter(options); iter; ++iter) {
- t_setattribute(iter.first().toInt64(), iter.second());
- }
- } else if (m_dbh.get()) {
- if (is_persistent) {
- assert(!shashkey.empty());
- g_persistentObjects->set(PDOConnection::PersistentKey, shashkey.data(),
- m_dbh.get());
- s_pdo_request_data->m_persistent_connections.insert(m_dbh.get());
- }
- m_dbh->driver = driver;
- for (ArrayIter iter(options); iter; ++iter) {
- t_setattribute(iter.first().toInt64(), iter.second());
- }
- }
- }
- Variant c_PDO::t_prepare(const String& statement,
- CArrRef options /* = null_array */) {
- assert(m_dbh->driver);
- strcpy(m_dbh->error_code, PDO_ERR_NONE);
- m_dbh->query_stmt = NULL;
- String clsname;
- Variant ctor_args;
- if (options.exists(PDO_ATTR_STATEMENT_CLASS)) {
- Variant opt = options[PDO_ATTR_STATEMENT_CLASS];
- if (!valid_statement_class(m_dbh, opt, clsname, ctor_args)) {
- return false;
- }
- } else {
- clsname = m_dbh->def_stmt_clsname;
- ctor_args = m_dbh->def_stmt_ctor_args;
- }
- Object ret = pdo_stmt_instantiate(m_dbh, clsname, ctor_args);
- if (ret.isNull()) {
- pdo_raise_impl_error
- (m_dbh, nullptr, "HY000",
- "failed to instantiate user-supplied statement class");
- PDO_HANDLE_DBH_ERR(m_dbh);
- return false;
- }
- c_PDOStatement *pdostmt = ret.getTyped<c_PDOStatement>();
- if (m_dbh->preparer(statement, &pdostmt->m_stmt, options)) {
- PDOStatement *stmt = pdostmt->m_stmt.get();
- assert(stmt);
- /* unconditionally keep this for later reference */
- stmt->query_string = statement;
- stmt->default_fetch_type = m_dbh->default_fetch_type;
- stmt->dbh = m_dbh;
- pdo_stmt_construct(stmt, ret, clsname, ctor_args);
- return ret;
- }
- PDO_HANDLE_DBH_ERR(m_dbh);
- return false;
- }
- bool c_PDO::t_begintransaction() {
- if (m_dbh->in_txn) {
- throw_pdo_exception(uninit_null(), uninit_null(), "There is already an active transaction");
- }
- if (m_dbh->begin()) {
- m_dbh->in_txn = 1;
- return true;
- }
- if (strcmp(m_dbh->error_code, PDO_ERR_NONE)) {
- pdo_handle_error(m_dbh, nullptr);
- }
- return false;
- }
- bool c_PDO::t_commit() {
- assert(m_dbh->driver);
- if (!m_dbh->in_txn) {
- throw_pdo_exception(uninit_null(), uninit_null(), "There is no active transaction");
- }
- if (m_dbh->commit()) {
- m_dbh->in_txn = 0;
- return true;
- }
- PDO_HANDLE_DBH_ERR(m_dbh);
- return false;
- }
- bool c_PDO::t_rollback() {
- assert(m_dbh->driver);
- if (!m_dbh->in_txn) {
- throw_pdo_exception(uninit_null(), uninit_null(), "There is no active transaction");
- }
- if (m_dbh->rollback()) {
- m_dbh->in_txn = 0;
- return true;
- }
- PDO_HANDLE_DBH_ERR(m_dbh);
- return false;
- }
- bool c_PDO::t_setattribute(int64_t attribute, CVarRef value) {
- assert(m_dbh->driver);
- #define PDO_LONG_PARAM_CHECK \
- if (!value.isInteger() && !value.isString() && !value.isBoolean()) { \
- pdo_raise_impl_error(m_dbh, nullptr, "HY000", \
- "attribute value must be an integer"); \
- PDO_HANDLE_DBH_ERR(m_dbh); \
- return false; \
- } \
- switch (attribute) {
- case PDO_ATTR_ERRMODE:
- PDO_LONG_PARAM_CHECK;
- switch (value.toInt64()) {
- case PDO_ERRMODE_SILENT:
- case PDO_ERRMODE_WARNING:
- case PDO_ERRMODE_EXCEPTION:
- m_dbh->error_mode = (PDOErrorMode)value.toInt64();
- return true;
- default:
- pdo_raise_impl_error(m_dbh, nullptr, "HY000", "invalid error mode");
- PDO_HANDLE_DBH_ERR(m_dbh);
- return false;
- }
- return false;
- case PDO_ATTR_CASE:
- PDO_LONG_PARAM_CHECK;
- switch (value.toInt64()) {
- case PDO_CASE_NATURAL:
- case PDO_CASE_UPPER:
- case PDO_CASE_LOWER:
- m_dbh->desired_case = (PDOCaseConversion)value.toInt64();
- return true;
- default:
- pdo_raise_impl_error(m_dbh, nullptr, "HY000",
- "invalid case folding mode");
- PDO_HANDLE_DBH_ERR(m_dbh);
- return false;
- }
- return false;
- case PDO_ATTR_ORACLE_NULLS:
- PDO_LONG_PARAM_CHECK;
- m_dbh->oracle_nulls = value.toInt64();
- return true;
- case PDO_ATTR_DEFAULT_FETCH_MODE:
- if (value.isArray()) {
- if (value.toArray().exists(0)) {
- Variant tmp = value[0];
- if (tmp.isInteger() && ((tmp.toInt64() == PDO_FETCH_INTO ||
- tmp.toInt64() == PDO_FETCH_CLASS))) {
- pdo_raise_impl_error(m_dbh, nullptr, "HY000",
- "FETCH_INTO and FETCH_CLASS are not yet "
- "supported as default fetch modes");
- return false;
- }
- }
- } else {
- PDO_LONG_PARAM_CHECK;
- }
- if (value.toInt64() == PDO_FETCH_USE_DEFAULT) {
- pdo_raise_impl_error(m_dbh, nullptr, "HY000", "invalid fetch mode type");
- return false;
- }
- m_dbh->default_fetch_type = (PDOFetchType)value.toInt64();
- return true;
- case PDO_ATTR_STRINGIFY_FETCHES:
- PDO_LONG_PARAM_CHECK;
- m_dbh->stringify = value.toInt64() ? 1 : 0;
- return true;
- case PDO_ATTR_STATEMENT_CLASS:
- {
- if (m_dbh->is_persistent) {
- pdo_raise_impl_error(m_dbh, nullptr, "HY000",
- "PDO::ATTR_STATEMENT_CLASS cannot be used "
- "with persistent PDO instances");
- PDO_HANDLE_DBH_ERR(m_dbh);
- return false;
- }
- String clsname;
- if (!valid_statement_class(m_dbh, value, clsname,
- m_dbh->def_stmt_ctor_args)) {
- return false;
- }
- m_dbh->def_stmt_clsname = clsname.c_str();
- return true;
- }
- }
- if (m_dbh->support(PDOConnection::MethodSetAttribute)) {
- strcpy(m_dbh->error_code, PDO_ERR_NONE);
- m_dbh->query_stmt = NULL;
- if (m_dbh->setAttribute(attribute, value)) {
- return true;
- }
- }
- if (attribute == PDO_ATTR_AUTOCOMMIT) {
- throw_pdo_exception(uninit_null(), uninit_null(),
- "The auto-commit mode cannot be changed for this "
- "driver");
- } else if (!m_dbh->support(PDOConnection::MethodSetAttribute)) {
- pdo_raise_impl_error(m_dbh, nullptr, "IM001",
- "driver does not support setting attributes");
- } else {
- PDO_HANDLE_DBH_ERR(m_dbh);
- }
- return false;
- }
- Variant c_PDO::t_getattribute(int64_t attribute) {
- assert(m_dbh->driver);
- strcpy(m_dbh->error_code, PDO_ERR_NONE);
- m_dbh->query_stmt = NULL;
- /* handle generic PDO-level atributes */
- switch (attribute) {
- case PDO_ATTR_PERSISTENT:
- return (bool)m_dbh->is_persistent;
- case PDO_ATTR_CASE:
- return (int64_t)m_dbh->desired_case;
- case PDO_ATTR_ORACLE_NULLS:
- return (int64_t)m_dbh->oracle_nulls;
- case PDO_ATTR_ERRMODE:
- return (int64_t)m_dbh->error_mode;
- case PDO_ATTR_DRIVER_NAME:
- return String(m_dbh->driver->getName());
- case PDO_ATTR_STATEMENT_CLASS: {
- Array ret;
- ret.append(String(m_dbh->def_stmt_clsname));
- if (!m_dbh->def_stmt_ctor_args.isNull()) {
- ret.append(m_dbh->def_stmt_ctor_args);
- }
- return ret;
- }
- case PDO_ATTR_DEFAULT_FETCH_MODE:
- return (int64_t)m_dbh->default_fetch_type;
- }
- if (!m_dbh->support(PDOConnection::MethodGetAttribute)) {
- pdo_raise_impl_error(m_dbh, nullptr, "IM001",
- "driver does not support getting attributes");
- return false;
- }
- Variant ret;
- switch (m_dbh->getAttribute(attribute, ret)) {
- case -1:
- PDO_HANDLE_DBH_ERR(m_dbh);
- return false;
- case 0:
- pdo_raise_impl_error(m_dbh, nullptr, "IM001",
- "driver does not support that attribute");
- return false;
- }
- return ret;
- }
- Variant c_PDO::t_exec(const String& query) {
- if (query.empty()) {
- pdo_raise_impl_error(m_dbh, nullptr, "HY000",
- "trying to execute an empty query");
- return false;
- }
- assert(m_dbh->driver);
- strcpy(m_dbh->error_code, PDO_ERR_NONE);
- m_dbh->query_stmt = NULL;
- int64_t ret = m_dbh->doer(query);
- if (ret == -1) {
- PDO_HANDLE_DBH_ERR(m_dbh);
- return false;
- }
- return ret;
- }
- Variant c_PDO::t_lastinsertid(const String& seqname /* = null_string */) {
- assert(m_dbh->driver);
- strcpy(m_dbh->error_code, PDO_ERR_NONE);
- m_dbh->query_stmt = NULL;
- if (!m_dbh->support(PDOConnection::MethodLastId)) {
- pdo_raise_impl_error(m_dbh, nullptr, "IM001",
- "driver does not support lastInsertId()");
- return false;
- }
- String ret = m_dbh->lastId(seqname.data());
- if (ret.empty()) {
- PDO_HANDLE_DBH_ERR(m_dbh);
- return false;
- }
- return ret;
- }
- Variant c_PDO::t_errorcode() {
- assert(m_dbh->driver);
- if (m_dbh->query_stmt) {
- return String(m_dbh->query_stmt->error_code, CopyString);
- }
- if (m_dbh->error_code[0] == '\0') {
- return uninit_null();
- }
- /**
- * Making sure that we fallback to the default implementation
- * if the dbh->error_code is not null.
- */
- return String(m_dbh->error_code, CopyString);
- }
- Array c_PDO::t_errorinfo() {
- assert(m_dbh->driver);
- Array ret;
- if (m_dbh->query_stmt) {
- ret.append(String(m_dbh->query_stmt->error_code, CopyString));
- } else {
- ret.append(String(m_dbh->error_code, CopyString));
- }
- if (m_dbh->support(PDOConnection::MethodFetchErr)) {
- m_dbh->fetchErr(m_dbh->query_stmt, ret);
- }
- /**
- * In order to be consistent, we have to make sure we add the good amount
- * of nulls depending on the current number of elements. We make a simple
- * difference and add the needed elements
- */
- int error_count = ret.size();
- int error_expected_count = 3;
- if (error_expected_count > error_count) {
- int error_count_diff = error_expected_count - error_count;
- for (int i = 0; i < error_count_diff; i++) {
- ret.append(uninit_null());
- }
- }
- return ret;
- }
- Variant c_PDO::t_query(const String& sql) {
- assert(m_dbh->driver);
- strcpy(m_dbh->error_code, PDO_ERR_NONE);
- m_dbh->query_stmt = NULL;
- Object ret = pdo_stmt_instantiate(m_dbh, m_dbh->def_stmt_clsname,
- m_dbh->def_stmt_ctor_args);
- if (ret.isNull()) {
- pdo_raise_impl_error
- (m_dbh, nullptr, "HY000",
- "failed to instantiate user supplied statement class");
- return uninit_null();
- }
- c_PDOStatement *pdostmt = ret.getTyped<c_PDOStatement>();
- if (m_dbh->preparer(sql, &pdostmt->m_stmt, Array())) {
- PDOStatement *stmt = pdostmt->m_stmt.get();
- assert(stmt);
- /* unconditiona…
Large files files are truncated, but you can click here to view the full file