2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2016 Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
19 #include "hphp/runtime/ext/pdo/ext_pdo.h"
23 #include <unordered_map>
25 #include "hphp/system/systemlib.h"
26 #include "hphp/util/string-vsnprintf.h"
28 #include "hphp/runtime/base/array-init.h"
29 #include "hphp/runtime/base/class-info.h"
30 #include "hphp/runtime/base/comparisons.h"
31 #include "hphp/runtime/base/file.h"
32 #include "hphp/runtime/base/ini-setting.h"
33 #include "hphp/runtime/base/request-event-handler.h"
34 #include "hphp/runtime/base/request-local.h"
35 #include "hphp/runtime/base/string-buffer.h"
36 #include "hphp/runtime/vm/jit/translator-inline.h"
38 #include "hphp/runtime/ext/array/ext_array.h"
39 #include "hphp/runtime/ext/pdo/pdo_driver.h"
40 #ifdef ENABLE_EXTENSION_PDO_MYSQL
41 #include "hphp/runtime/ext/pdo_mysql/pdo_mysql.h"
43 #ifdef ENABLE_EXTENSION_PDO_SQLITE
44 #include "hphp/runtime/ext/pdo_sqlite/pdo_sqlite.h"
46 #include "hphp/runtime/ext/std/ext_std_classobj.h"
47 #include "hphp/runtime/ext/std/ext_std_function.h"
48 #include "hphp/runtime/ext/stream/ext_stream.h"
49 #include "hphp/runtime/ext/string/ext_string.h"
51 #define PDO_HANDLE_DBH_ERR(dbh) \
52 if (strcmp(dbh->conn()->error_code, PDO_ERR_NONE)) { \
53 pdo_handle_error(dbh, nullptr); \
56 #define PDO_HANDLE_STMT_ERR(stmt) \
57 if (strcmp(stmt->error_code, PDO_ERR_NONE)) { \
58 pdo_handle_error(stmt->dbh, stmt); \
64 ///////////////////////////////////////////////////////////////////////////////
67 const int64_t q_PDO$$PARAM_BOOL
= PDO_PARAM_BOOL
;
68 const int64_t q_PDO$$PARAM_NULL
= PDO_PARAM_NULL
;
69 const int64_t q_PDO$$PARAM_INT
= PDO_PARAM_INT
;
70 const int64_t q_PDO$$PARAM_STR
= PDO_PARAM_STR
;
71 const int64_t q_PDO$$PARAM_LOB
= PDO_PARAM_LOB
;
72 const int64_t q_PDO$$PARAM_STMT
= PDO_PARAM_STMT
;
73 const int64_t q_PDO$$PARAM_INPUT_OUTPUT
= PDO_PARAM_INPUT_OUTPUT
;
75 const int64_t q_PDO$$PARAM_EVT_ALLOC
= PDO_PARAM_EVT_ALLOC
;
76 const int64_t q_PDO$$PARAM_EVT_FREE
= PDO_PARAM_EVT_FREE
;
77 const int64_t q_PDO$$PARAM_EVT_EXEC_PRE
= PDO_PARAM_EVT_EXEC_PRE
;
78 const int64_t q_PDO$$PARAM_EVT_EXEC_POST
= PDO_PARAM_EVT_EXEC_POST
;
79 const int64_t q_PDO$$PARAM_EVT_FETCH_PRE
= PDO_PARAM_EVT_FETCH_PRE
;
80 const int64_t q_PDO$$PARAM_EVT_FETCH_POST
= PDO_PARAM_EVT_FETCH_POST
;
81 const int64_t q_PDO$$PARAM_EVT_NORMALIZE
= PDO_PARAM_EVT_NORMALIZE
;
83 const int64_t q_PDO$$FETCH_USE_DEFAULT
= PDO_FETCH_USE_DEFAULT
;
84 const int64_t q_PDO$$FETCH_LAZY
= PDO_FETCH_LAZY
;
85 const int64_t q_PDO$$FETCH_ASSOC
= PDO_FETCH_ASSOC
;
86 const int64_t q_PDO$$FETCH_NUM
= PDO_FETCH_NUM
;
87 const int64_t q_PDO$$FETCH_BOTH
= PDO_FETCH_BOTH
;
88 const int64_t q_PDO$$FETCH_OBJ
= PDO_FETCH_OBJ
;
89 const int64_t q_PDO$$FETCH_BOUND
= PDO_FETCH_BOUND
;
90 const int64_t q_PDO$$FETCH_COLUMN
= PDO_FETCH_COLUMN
;
91 const int64_t q_PDO$$FETCH_CLASS
= PDO_FETCH_CLASS
;
92 const int64_t q_PDO$$FETCH_INTO
= PDO_FETCH_INTO
;
93 const int64_t q_PDO$$FETCH_FUNC
= PDO_FETCH_FUNC
;
94 const int64_t q_PDO$$FETCH_GROUP
= PDO_FETCH_GROUP
;
95 const int64_t q_PDO$$FETCH_UNIQUE
= PDO_FETCH_UNIQUE
;
96 const int64_t q_PDO$$FETCH_KEY_PAIR
= PDO_FETCH_KEY_PAIR
;
97 const int64_t q_PDO$$FETCH_CLASSTYPE
= PDO_FETCH_CLASSTYPE
;
98 const int64_t q_PDO$$FETCH_SERIALIZE
= PDO_FETCH_SERIALIZE
;
99 const int64_t q_PDO$$FETCH_PROPS_LATE
= PDO_FETCH_PROPS_LATE
;
100 const int64_t q_PDO$$FETCH_NAMED
= PDO_FETCH_NAMED
;
102 const int64_t q_PDO$$ATTR_AUTOCOMMIT
= PDO_ATTR_AUTOCOMMIT
;
103 const int64_t q_PDO$$ATTR_PREFETCH
= PDO_ATTR_PREFETCH
;
104 const int64_t q_PDO$$ATTR_TIMEOUT
= PDO_ATTR_TIMEOUT
;
105 const int64_t q_PDO$$ATTR_ERRMODE
= PDO_ATTR_ERRMODE
;
106 const int64_t q_PDO$$ATTR_SERVER_VERSION
= PDO_ATTR_SERVER_VERSION
;
107 const int64_t q_PDO$$ATTR_CLIENT_VERSION
= PDO_ATTR_CLIENT_VERSION
;
108 const int64_t q_PDO$$ATTR_SERVER_INFO
= PDO_ATTR_SERVER_INFO
;
109 const int64_t q_PDO$$ATTR_CONNECTION_STATUS
= PDO_ATTR_CONNECTION_STATUS
;
110 const int64_t q_PDO$$ATTR_CASE
= PDO_ATTR_CASE
;
111 const int64_t q_PDO$$ATTR_CURSOR_NAME
= PDO_ATTR_CURSOR_NAME
;
112 const int64_t q_PDO$$ATTR_CURSOR
= PDO_ATTR_CURSOR
;
113 const int64_t q_PDO$$ATTR_ORACLE_NULLS
= PDO_ATTR_ORACLE_NULLS
;
114 const int64_t q_PDO$$ATTR_PERSISTENT
= PDO_ATTR_PERSISTENT
;
115 const int64_t q_PDO$$ATTR_STATEMENT_CLASS
= PDO_ATTR_STATEMENT_CLASS
;
116 const int64_t q_PDO$$ATTR_FETCH_TABLE_NAMES
= PDO_ATTR_FETCH_TABLE_NAMES
;
117 const int64_t q_PDO$$ATTR_FETCH_CATALOG_NAMES
= PDO_ATTR_FETCH_CATALOG_NAMES
;
118 const int64_t q_PDO$$ATTR_DRIVER_NAME
= PDO_ATTR_DRIVER_NAME
;
119 const int64_t q_PDO$$ATTR_STRINGIFY_FETCHES
= PDO_ATTR_STRINGIFY_FETCHES
;
120 const int64_t q_PDO$$ATTR_MAX_COLUMN_LEN
= PDO_ATTR_MAX_COLUMN_LEN
;
121 const int64_t q_PDO$$ATTR_EMULATE_PREPARES
= PDO_ATTR_EMULATE_PREPARES
;
122 const int64_t q_PDO$$ATTR_DEFAULT_FETCH_MODE
= PDO_ATTR_DEFAULT_FETCH_MODE
;
124 const int64_t q_PDO$$ERRMODE_SILENT
= PDO_ERRMODE_SILENT
;
125 const int64_t q_PDO$$ERRMODE_WARNING
= PDO_ERRMODE_WARNING
;
126 const int64_t q_PDO$$ERRMODE_EXCEPTION
= PDO_ERRMODE_EXCEPTION
;
128 const int64_t q_PDO$$CASE_NATURAL
= PDO_CASE_NATURAL
;
129 const int64_t q_PDO$$CASE_LOWER
= PDO_CASE_LOWER
;
130 const int64_t q_PDO$$CASE_UPPER
= PDO_CASE_UPPER
;
132 const int64_t q_PDO$$NULL_NATURAL
= PDO_NULL_NATURAL
;
133 const int64_t q_PDO$$NULL_EMPTY_STRING
= PDO_NULL_EMPTY_STRING
;
134 const int64_t q_PDO$$NULL_TO_STRING
= PDO_NULL_TO_STRING
;
136 const StaticString q_PDO$$
ERR_NONE(PDO_ERR_NONE
);
138 const int64_t q_PDO$$FETCH_ORI_NEXT
= PDO_FETCH_ORI_NEXT
;
139 const int64_t q_PDO$$FETCH_ORI_PRIOR
= PDO_FETCH_ORI_PRIOR
;
140 const int64_t q_PDO$$FETCH_ORI_FIRST
= PDO_FETCH_ORI_FIRST
;
141 const int64_t q_PDO$$FETCH_ORI_LAST
= PDO_FETCH_ORI_LAST
;
142 const int64_t q_PDO$$FETCH_ORI_ABS
= PDO_FETCH_ORI_ABS
;
143 const int64_t q_PDO$$FETCH_ORI_REL
= PDO_FETCH_ORI_REL
;
145 const int64_t q_PDO$$CURSOR_FWDONLY
= PDO_CURSOR_FWDONLY
;
146 const int64_t q_PDO$$CURSOR_SCROLL
= PDO_CURSOR_SCROLL
;
148 ///////////////////////////////////////////////////////////////////////////////
150 #ifdef ENABLE_EXTENSION_PDO_MYSQL
151 const int64_t q_PDO$$MYSQL_ATTR_USE_BUFFERED_QUERY
=
152 PDO_MYSQL_ATTR_USE_BUFFERED_QUERY
;
153 const int64_t q_PDO$$MYSQL_ATTR_LOCAL_INFILE
= PDO_MYSQL_ATTR_LOCAL_INFILE
;
154 const int64_t q_PDO$$MYSQL_ATTR_MAX_BUFFER_SIZE
=
155 PDO_MYSQL_ATTR_MAX_BUFFER_SIZE
;
156 const int64_t q_PDO$$MYSQL_ATTR_INIT_COMMAND
= PDO_MYSQL_ATTR_INIT_COMMAND
;
157 const int64_t q_PDO$$MYSQL_ATTR_READ_DEFAULT_FILE
=
158 PDO_MYSQL_ATTR_READ_DEFAULT_FILE
;
159 const int64_t q_PDO$$MYSQL_ATTR_READ_DEFAULT_GROUP
=
160 PDO_MYSQL_ATTR_READ_DEFAULT_GROUP
;
161 const int64_t q_PDO$$MYSQL_ATTR_COMPRESS
= PDO_MYSQL_ATTR_COMPRESS
;
162 const int64_t q_PDO$$MYSQL_ATTR_DIRECT_QUERY
= PDO_MYSQL_ATTR_DIRECT_QUERY
;
163 const int64_t q_PDO$$MYSQL_ATTR_FOUND_ROWS
= PDO_MYSQL_ATTR_FOUND_ROWS
;
164 const int64_t q_PDO$$MYSQL_ATTR_IGNORE_SPACE
= PDO_MYSQL_ATTR_IGNORE_SPACE
;
167 ///////////////////////////////////////////////////////////////////////////////
168 // extension functions
170 Array
f_pdo_drivers() {
171 Array ret
= Array::Create();
172 const PDODriverMap
&drivers
= PDODriver::GetDrivers();
173 for (PDODriverMap::const_iterator iter
= drivers
.begin();
174 iter
!= drivers
.end(); ++iter
) {
175 ret
.append(iter
->second
->getName());
180 ///////////////////////////////////////////////////////////////////////////////
183 struct pdo_sqlstate_info
{
188 static const struct pdo_sqlstate_info err_initializer
[] = {
189 { "00000", "No error" },
190 { "01000", "Warning" },
191 { "01001", "Cursor operation conflict" },
192 { "01002", "Disconnect error" },
193 { "01003", "NULL value eliminated in set function" },
194 { "01004", "String data, right truncated" },
195 { "01006", "Privilege not revoked" },
196 { "01007", "Privilege not granted" },
197 { "01008", "Implicit zero bit padding" },
198 { "0100C", "Dynamic result sets returned" },
199 { "01P01", "Deprecated feature" },
200 { "01S00", "Invalid connection string attribute" },
201 { "01S01", "Error in row" },
202 { "01S02", "Option value changed" },
204 "Attempt to fetch before the result set returned the first rowset" },
205 { "01S07", "Fractional truncation" },
206 { "01S08", "Error saving File DSN" },
207 { "01S09", "Invalid keyword" },
208 { "02000", "No data" },
209 { "02001", "No additional dynamic result sets returned" },
210 { "03000", "Sql statement not yet complete" },
211 { "07002", "COUNT field incorrect" },
212 { "07005", "Prepared statement not a cursor-specification" },
213 { "07006", "Restricted data type attribute violation" },
214 { "07009", "Invalid descriptor index" },
215 { "07S01", "Invalid use of default parameter" },
216 { "08000", "Connection exception" },
217 { "08001", "Client unable to establish connection" },
218 { "08002", "Connection name in use" },
219 { "08003", "Connection does not exist" },
220 { "08004", "Server rejected the connection" },
221 { "08006", "Connection failure" },
222 { "08007", "Connection failure during transaction" },
223 { "08S01", "Communication link failure" },
224 { "09000", "Triggered action exception" },
225 { "0A000", "Feature not supported" },
226 { "0B000", "Invalid transaction initiation" },
227 { "0F000", "Locator exception" },
228 { "0F001", "Invalid locator specification" },
229 { "0L000", "Invalid grantor" },
230 { "0LP01", "Invalid grant operation" },
231 { "0P000", "Invalid role specification" },
232 { "21000", "Cardinality violation" },
233 { "21S01", "Insert value list does not match column list" },
234 { "21S02", "Degree of derived table does not match column list" },
235 { "22000", "Data exception" },
236 { "22001", "String data, right truncated" },
237 { "22002", "Indicator variable required but not supplied" },
238 { "22003", "Numeric value out of range" },
239 { "22004", "Null value not allowed" },
240 { "22005", "Error in assignment" },
241 { "22007", "Invalid datetime format" },
242 { "22008", "Datetime field overflow" },
243 { "22009", "Invalid time zone displacement value" },
244 { "2200B", "Escape character conflict" },
245 { "2200C", "Invalid use of escape character" },
246 { "2200D", "Invalid escape octet" },
247 { "2200F", "Zero length character string" },
248 { "2200G", "Most specific type mismatch" },
249 { "22010", "Invalid indicator parameter value" },
250 { "22011", "Substring error" },
251 { "22012", "Division by zero" },
252 { "22015", "Interval field overflow" },
253 { "22018", "Invalid character value for cast specification" },
254 { "22019", "Invalid escape character" },
255 { "2201B", "Invalid regular expression" },
256 { "2201E", "Invalid argument for logarithm" },
257 { "2201F", "Invalid argument for power function" },
258 { "2201G", "Invalid argument for width bucket function" },
259 { "22020", "Invalid limit value" },
260 { "22021", "Character not in repertoire" },
261 { "22022", "Indicator overflow" },
262 { "22023", "Invalid parameter value" },
263 { "22024", "Unterminated c string" },
264 { "22025", "Invalid escape sequence" },
265 { "22026", "String data, length mismatch" },
266 { "22027", "Trim error" },
267 { "2202E", "Array subscript error" },
268 { "22P01", "Floating point exception" },
269 { "22P02", "Invalid text representation" },
270 { "22P03", "Invalid binary representation" },
271 { "22P04", "Bad copy file format" },
272 { "22P05", "Untranslatable character" },
273 { "23000", "Integrity constraint violation" },
274 { "23001", "Restrict violation" },
275 { "23502", "Not null violation" },
276 { "23503", "Foreign key violation" },
277 { "23505", "Unique violation" },
278 { "23514", "Check violation" },
279 { "24000", "Invalid cursor state" },
280 { "25000", "Invalid transaction state" },
281 { "25001", "Active sql transaction" },
282 { "25002", "Branch transaction already active" },
283 { "25003", "Inappropriate access mode for branch transaction" },
284 { "25004", "Inappropriate isolation level for branch transaction" },
285 { "25005", "No active sql transaction for branch transaction" },
286 { "25006", "Read only sql transaction" },
287 { "25007", "Schema and data statement mixing not supported" },
288 { "25008", "Held cursor requires same isolation level" },
289 { "25P01", "No active sql transaction" },
290 { "25P02", "In failed sql transaction" },
291 { "25S01", "Transaction state" },
292 { "25S02", "Transaction is still active" },
293 { "25S03", "Transaction is rolled back" },
294 { "26000", "Invalid sql statement name" },
295 { "27000", "Triggered data change violation" },
296 { "28000", "Invalid authorization specification" },
297 { "2B000", "Dependent privilege descriptors still exist" },
298 { "2BP01", "Dependent objects still exist" },
299 { "2D000", "Invalid transaction termination" },
300 { "2F000", "Sql routine exception" },
301 { "2F002", "Modifying sql data not permitted" },
302 { "2F003", "Prohibited sql statement attempted" },
303 { "2F004", "Reading sql data not permitted" },
304 { "2F005", "Function executed no return statement" },
305 { "34000", "Invalid cursor name" },
306 { "38000", "External routine exception" },
307 { "38001", "Containing sql not permitted" },
308 { "38002", "Modifying sql data not permitted" },
309 { "38003", "Prohibited sql statement attempted" },
310 { "38004", "Reading sql data not permitted" },
311 { "39000", "External routine invocation exception" },
312 { "39001", "Invalid sqlstate returned" },
313 { "39004", "Null value not allowed" },
314 { "39P01", "Trigger protocol violated" },
315 { "39P02", "Srf protocol violated" },
316 { "3B000", "Savepoint exception" },
317 { "3B001", "Invalid savepoint specification" },
318 { "3C000", "Duplicate cursor name" },
319 { "3D000", "Invalid catalog name" },
320 { "3F000", "Invalid schema name" },
321 { "40000", "Transaction rollback" },
322 { "40001", "Serialization failure" },
323 { "40002", "Transaction integrity constraint violation" },
324 { "40003", "Statement completion unknown" },
325 { "40P01", "Deadlock detected" },
326 { "42000", "Syntax error or access violation" },
327 { "42501", "Insufficient privilege" },
328 { "42601", "Syntax error" },
329 { "42602", "Invalid name" },
330 { "42611", "Invalid column definition" },
331 { "42622", "Name too long" },
332 { "42701", "Duplicate column" },
333 { "42702", "Ambiguous column" },
334 { "42703", "Undefined column" },
335 { "42704", "Undefined object" },
336 { "42710", "Duplicate object" },
337 { "42712", "Duplicate alias" },
338 { "42723", "Duplicate function" },
339 { "42725", "Ambiguous function" },
340 { "42803", "Grouping error" },
341 { "42804", "Datatype mismatch" },
342 { "42809", "Wrong object type" },
343 { "42830", "Invalid foreign key" },
344 { "42846", "Cannot coerce" },
345 { "42883", "Undefined function" },
346 { "42939", "Reserved name" },
347 { "42P01", "Undefined table" },
348 { "42P02", "Undefined parameter" },
349 { "42P03", "Duplicate cursor" },
350 { "42P04", "Duplicate database" },
351 { "42P05", "Duplicate prepared statement" },
352 { "42P06", "Duplicate schema" },
353 { "42P07", "Duplicate table" },
354 { "42P08", "Ambiguous parameter" },
355 { "42P09", "Ambiguous alias" },
356 { "42P10", "Invalid column reference" },
357 { "42P11", "Invalid cursor definition" },
358 { "42P12", "Invalid database definition" },
359 { "42P13", "Invalid function definition" },
360 { "42P14", "Invalid prepared statement definition" },
361 { "42P15", "Invalid schema definition" },
362 { "42P16", "Invalid table definition" },
363 { "42P17", "Invalid object definition" },
364 { "42P18", "Indeterminate datatype" },
365 { "42S01", "Base table or view already exists" },
366 { "42S02", "Base table or view not found" },
367 { "42S11", "Index already exists" },
368 { "42S12", "Index not found" },
369 { "42S21", "Column already exists" },
370 { "42S22", "Column not found" },
371 { "44000", "WITH CHECK OPTION violation" },
372 { "53000", "Insufficient resources" },
373 { "53100", "Disk full" },
374 { "53200", "Out of memory" },
375 { "53300", "Too many connections" },
376 { "54000", "Program limit exceeded" },
377 { "54001", "Statement too complex" },
378 { "54011", "Too many columns" },
379 { "54023", "Too many arguments" },
380 { "55000", "Object not in prerequisite state" },
381 { "55006", "Object in use" },
382 { "55P02", "Cant change runtime param" },
383 { "55P03", "Lock not available" },
384 { "57000", "Operator intervention" },
385 { "57014", "Query canceled" },
386 { "57P01", "Admin shutdown" },
387 { "57P02", "Crash shutdown" },
388 { "57P03", "Cannot connect now" },
389 { "58030", "Io error" },
390 { "58P01", "Undefined file" },
391 { "58P02", "Duplicate file" },
392 { "F0000", "Config file error" },
393 { "F0001", "Lock file exists" },
394 { "HY000", "General error" },
395 { "HY001", "Memory allocation error" },
396 { "HY003", "Invalid application buffer type" },
397 { "HY004", "Invalid SQL data type" },
398 { "HY007", "Associated statement is not prepared" },
399 { "HY008", "Operation canceled" },
400 { "HY009", "Invalid use of null pointer" },
401 { "HY010", "Function sequence error" },
402 { "HY011", "Attribute cannot be set now" },
403 { "HY012", "Invalid transaction operation code" },
404 { "HY013", "Memory management error" },
405 { "HY014", "Limit on the number of handles exceeded" },
406 { "HY015", "No cursor name available" },
407 { "HY016", "Cannot modify an implementation row descriptor" },
408 { "HY017", "Invalid use of an automatically allocated descriptor handle" },
409 { "HY018", "Server declined cancel request" },
410 { "HY019", "Non-character and non-binary data sent in pieces" },
411 { "HY020", "Attempt to concatenate a null value" },
412 { "HY021", "Inconsistent descriptor information" },
413 { "HY024", "Invalid attribute value" },
414 { "HY090", "Invalid string or buffer length" },
415 { "HY091", "Invalid descriptor field identifier" },
416 { "HY092", "Invalid attribute/option identifier" },
417 { "HY093", "Invalid parameter number" },
418 { "HY095", "Function type out of range" },
419 { "HY096", "Invalid information type" },
420 { "HY097", "Column type out of range" },
421 { "HY098", "Scope type out of range" },
422 { "HY099", "Nullable type out of range" },
423 { "HY100", "Uniqueness option type out of range" },
424 { "HY101", "Accuracy option type out of range" },
425 { "HY103", "Invalid retrieval code" },
426 { "HY104", "Invalid precision or scale value" },
427 { "HY105", "Invalid parameter type" },
428 { "HY106", "Fetch type out of range" },
429 { "HY107", "Row value out of range" },
430 { "HY109", "Invalid cursor position" },
431 { "HY110", "Invalid driver completion" },
432 { "HY111", "Invalid bookmark value" },
433 { "HYC00", "Optional feature not implemented" },
434 { "HYT00", "Timeout expired" },
435 { "HYT01", "Connection timeout expired" },
436 { "IM001", "Driver does not support this function" },
437 { "IM002", "Data source name not found and no default driver specified" },
438 { "IM003", "Specified driver could not be loaded" },
439 { "IM004", "Driver's SQLAllocHandle on SQL_HANDLE_ENV failed" },
440 { "IM005", "Driver's SQLAllocHandle on SQL_HANDLE_DBC failed" },
441 { "IM006", "Driver's SQLSetConnectAttr failed" },
442 { "IM007", "No data source or driver specified; dialog prohibited" },
443 { "IM008", "Dialog failed" },
444 { "IM009", "Unable to load translation DLL" },
445 { "IM010", "Data source name too long" },
446 { "IM011", "Driver name too long" },
447 { "IM012", "DRIVER keyword syntax error" },
448 { "IM013", "Trace file error" },
449 { "IM014", "Invalid name of File DSN" },
450 { "IM015", "Corrupt file data source" },
451 { "P0000", "Plpgsql error" },
452 { "P0001", "Raise exception" },
453 { "XX000", "Internal error" },
454 { "XX001", "Data corrupted" },
455 { "XX002", "Index corrupted" }
458 struct PDOErrorHash
: private hphp_const_char_map
<const char *> {
460 for (unsigned int i
= 0;
461 i
< sizeof(err_initializer
)/sizeof(err_initializer
[0]); i
++) {
462 const struct pdo_sqlstate_info
*info
= &err_initializer
[i
];
463 (*this)[info
->state
] = info
->desc
;
467 const char *description(const char *state
) {
468 const_iterator iter
= find(state
);
472 return "<<Unknown error>>";
475 static PDOErrorHash s_err_hash
;
479 s_message("message"),
480 s_errorInfo("errorInfo"),
481 s_PDOException("PDOException");
483 void throw_pdo_exception(const Variant
& code
, const Variant
& info
,
484 const char *fmt
, ...) {
485 auto obj
= SystemLib::AllocPDOExceptionObject();
486 obj
->o_set(s_code
, code
, s_PDOException
);
491 string_vsnprintf(msg
, fmt
, ap
);
492 obj
->o_set(s_message
, String(msg
), s_PDOException
);
495 if (!info
.isNull()) {
496 obj
->o_set(s_errorInfo
, info
, s_PDOException
);
501 void pdo_raise_impl_error(sp_PDOResource rsrc
, PDOStatement
* stmt
,
502 const char *sqlstate
, const char *supp
) {
503 auto const& dbh
= rsrc
->conn();
505 PDOErrorType
*pdo_err
= &dbh
->error_code
;
507 pdo_err
= &stmt
->error_code
;
509 setPDOError(*pdo_err
, sqlstate
);
511 const char *msg
= s_err_hash
.description(sqlstate
);
512 string err
= "SQLSTATE["; err
+= sqlstate
; err
+= "]: "; err
+= msg
;
514 err
+= ": "; err
+= supp
;
517 if (dbh
->error_mode
!= PDO_ERRMODE_EXCEPTION
) {
518 raise_warning("%s", err
.c_str());
521 info
.append(String(*pdo_err
, CopyString
));
523 throw_pdo_exception(String(sqlstate
, CopyString
), info
, "%s", err
.c_str());
527 void pdo_raise_impl_error(sp_PDOResource rsrc
, sp_PDOStatement stmt
,
528 const char *sqlstate
, const char *supp
) {
529 pdo_raise_impl_error(rsrc
, stmt
.get(), sqlstate
, supp
);
534 void pdo_handle_error(sp_PDOResource rsrc
, PDOStatement
* stmt
) {
535 auto const& dbh
= rsrc
->conn();
537 if (dbh
->error_mode
== PDO_ERRMODE_SILENT
) {
540 PDOErrorType
*pdo_err
= &dbh
->error_code
;
542 pdo_err
= &stmt
->error_code
;
545 /* hash sqlstate to error messages */
546 const char *msg
= s_err_hash
.description(*pdo_err
);
548 int64_t native_code
= 0;
551 if (dbh
->support(PDOConnection::MethodFetchErr
)) {
552 info
= Array::Create();
553 info
.append(String(*pdo_err
, CopyString
));
554 if (dbh
->fetchErr(stmt
, info
)) {
555 if (info
.exists(1)) {
556 native_code
= info
[1].toInt64();
558 if (info
.exists(2)) {
559 supp
= info
[2].toString();
564 string err
= "SQLSTATE["; err
+= *pdo_err
; err
+= "]: "; err
+= msg
;
566 err
+= ": "; err
+= String(native_code
).data();
567 err
+= " "; err
+= supp
.data();
570 if (dbh
->error_mode
!= PDO_ERRMODE_EXCEPTION
) {
571 raise_warning("%s", err
.c_str());
573 throw_pdo_exception(String(*pdo_err
, CopyString
), info
, "%s", err
.c_str());
577 void pdo_handle_error(sp_PDOResource rsrc
, sp_PDOStatement stmt
) {
578 pdo_handle_error(rsrc
, stmt
.get());
583 ///////////////////////////////////////////////////////////////////////////////
584 // helpers for PDO class
586 static inline int64_t pdo_attr_lval(const Array
& options
, PDOAttributeType name
,
588 if (options
.exists(name
)) {
589 return options
[name
].toInt64();
594 static Object
pdo_stmt_instantiate(sp_PDOResource dbh
, const String
& clsname
,
595 const Variant
& ctor_args
) {
596 String name
= clsname
;
598 name
= "PDOStatement";
600 if (!ctor_args
.isNull() && !ctor_args
.isArray()) {
601 pdo_raise_impl_error(dbh
, nullptr, "HY000",
602 "constructor arguments must be passed as an array");
605 Class
* cls
= Unit::loadClass(name
.get());
612 static void pdo_stmt_construct(sp_PDOStatement stmt
, Object object
,
613 const String
& clsname
,
614 const Variant
& ctor_args
) {
615 object
->o_set("queryString", stmt
->query_string
);
616 if (clsname
.empty()) {
619 Class
* cls
= Unit::loadClass(clsname
.get());
624 ObjectData
* inst
= object
.get();
625 g_context
->invokeFunc(&ret
, cls
->getCtor(), ctor_args
.toArray(), inst
);
626 tvRefcountedDecRef(&ret
);
629 static bool valid_statement_class(sp_PDOResource dbh
, const Variant
& opt
,
630 String
&clsname
, Variant
&ctor_args
) {
631 if (!opt
.isArray() || !opt
.toArray().exists(0) ||
632 !opt
.toArray()[0].isString() ||
633 !HHVM_FN(class_exists
)(opt
.toArray()[0].toString())) {
635 (dbh
, nullptr, "HY000",
636 "PDO::ATTR_STATEMENT_CLASS requires format array(classname, "
637 "array(ctor_args)); the classname must be a string specifying "
638 "an existing class");
639 PDO_HANDLE_DBH_ERR(dbh
);
642 clsname
= opt
.toArray()[0].toString();
643 if (clsname
== String("PDOStatement")) {
644 ctor_args
= Variant(Array());
647 if (!HHVM_FN(is_a
)(clsname
, "PDOStatement", /* allow_string */ true)) {
649 (dbh
, nullptr, "HY000",
650 "user-supplied statement class must be derived from PDOStatement");
651 PDO_HANDLE_DBH_ERR(dbh
);
654 HPHP::Class
* cls
= HPHP::Unit::loadClass(clsname
.get());
656 const HPHP::Func
* method
= cls
->getDeclaredCtor();
657 if (method
&& method
->isPublic()) {
659 (dbh
, nullptr, "HY000",
660 "user-supplied statement class cannot have a public constructor");
661 PDO_HANDLE_DBH_ERR(dbh
);
665 if (opt
.toArray().exists(1)) {
666 Variant item
= opt
.toArray()[1];
667 if (!item
.isArray()) {
669 (dbh
, nullptr, "HY000",
670 "PDO::ATTR_STATEMENT_CLASS requires format array(classname, "
671 "ctor_args); ctor_args must be an array");
672 PDO_HANDLE_DBH_ERR(dbh
);
680 static bool pdo_stmt_describe_columns(sp_PDOStatement stmt
) {
681 for (int col
= 0; col
< stmt
->column_count
; col
++) {
682 if (!stmt
->describer(col
)) {
686 auto column
= cast
<PDOColumn
>(stmt
->columns
[col
]);
688 /* if we are applying case conversions on column names, do so now */
689 if (stmt
->dbh
->conn()->native_case
!= stmt
->dbh
->conn()->desired_case
&&
690 stmt
->dbh
->conn()->desired_case
!= PDO_CASE_NATURAL
) {
691 switch (stmt
->dbh
->conn()->desired_case
) {
693 column
->name
= HHVM_FN(strtoupper
)(column
->name
);
696 column
->name
= HHVM_FN(strtolower
)(column
->name
);
702 if (stmt
->bound_columns
.exists(column
->name
)) {
703 auto param
= cast
<PDOBoundParam
>(stmt
->bound_columns
[column
->name
]);
704 param
->paramno
= col
;
710 static bool pdo_stmt_verify_mode(sp_PDOStatement stmt
, int64_t mode
,
712 int flags
= mode
& PDO_FETCH_FLAGS
;
713 mode
= mode
& ~PDO_FETCH_FLAGS
;
715 if (mode
< 0 || mode
> PDO_FETCH__MAX
) {
716 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000", "invalid fetch mode");
720 if (mode
== PDO_FETCH_USE_DEFAULT
) {
721 flags
= stmt
->default_fetch_type
& PDO_FETCH_FLAGS
;
722 mode
= stmt
->default_fetch_type
& ~PDO_FETCH_FLAGS
;
728 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
729 "PDO::FETCH_FUNC is only allowed in "
730 "PDOStatement::fetchAll()");
737 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
738 "PDO::FETCH_LAZY can't be used with "
739 "PDOStatement::fetchAll()");
744 if ((flags
& PDO_FETCH_SERIALIZE
) == PDO_FETCH_SERIALIZE
) {
745 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
746 "PDO::FETCH_SERIALIZE can only be used "
747 "together with PDO::FETCH_CLASS");
750 if ((flags
& PDO_FETCH_CLASSTYPE
) == PDO_FETCH_CLASSTYPE
) {
751 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
752 "PDO::FETCH_CLASSTYPE can only be used "
753 "together with PDO::FETCH_CLASS");
756 if (mode
>= PDO_FETCH__MAX
) {
757 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000", "invalid fetch mode");
762 case PDO_FETCH_CLASS
:
768 static bool do_fetch_class_prepare(sp_PDOStatement stmt
) {
769 String clsname
= stmt
->fetch
.clsname
;
770 if (clsname
.empty()) {
771 stmt
->fetch
.clsname
= "stdclass";
773 stmt
->fetch
.constructor
= empty_string(); //NULL;
774 HPHP::Class
* cls
= HPHP::Unit::loadClass(clsname
.get());
776 const HPHP::Func
* method
= cls
->getDeclaredCtor();
778 stmt
->fetch
.constructor
= method
->nameStr();
782 if (!stmt
->fetch
.ctor_args
.isNull()) {
783 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
784 "user-supplied class does not have a constructor, "
785 "use NULL for the ctor_params parameter, or simply "
789 return true; /* no ctor no args is also ok */
792 static bool pdo_stmt_set_fetch_mode(sp_PDOStatement stmt
, int _argc
,
793 int64_t mode
, const Array
& _argv
) {
794 _argc
= _argv
.size() + 1;
796 if (stmt
->default_fetch_type
== PDO_FETCH_INTO
) {
797 stmt
->fetch
.into
.unset();
799 stmt
->default_fetch_type
= PDO_FETCH_BOTH
;
801 if (!pdo_stmt_verify_mode(stmt
, mode
, false)) {
802 setPDOErrorNone(stmt
->error_code
);
806 int flags
= mode
& PDO_FETCH_FLAGS
;
808 switch (mode
& ~PDO_FETCH_FLAGS
) {
809 case PDO_FETCH_USE_DEFAULT
:
811 case PDO_FETCH_ASSOC
:
815 case PDO_FETCH_BOUND
:
816 case PDO_FETCH_NAMED
:
817 case PDO_FETCH_KEY_PAIR
:
819 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
820 "fetch mode doesn't allow any extra arguments");
826 case PDO_FETCH_COLUMN
:
828 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
829 "fetch mode requires the colno argument");
830 } else if (!_argv
[0].isInteger()) {
831 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
832 "colno must be an integer");
834 stmt
->fetch
.column
= _argv
[0].toInt64();
839 case PDO_FETCH_CLASS
:
840 /* Gets its class name from 1st column */
841 if ((flags
& PDO_FETCH_CLASSTYPE
) == PDO_FETCH_CLASSTYPE
) {
843 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
844 "fetch mode doesn't allow any extra arguments");
846 stmt
->fetch
.clsname
.clear();
851 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
852 "fetch mode requires the classname argument");
853 } else if (_argc
> 3) {
854 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
855 "too many arguments");
856 } else if (!_argv
[0].isString()) {
857 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
858 "classname must be a string");
860 retval
= HHVM_FN(class_exists
)(_argv
[0].toString());
862 stmt
->fetch
.clsname
= _argv
[0].toString();
868 stmt
->fetch
.ctor_args
.unset();
870 if (!_argv
[1].isNull() && !_argv
[1].isArray()) {
871 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
872 "ctor_args must be either NULL or an array");
875 stmt
->fetch
.ctor_args
= _argv
[1];
880 do_fetch_class_prepare(stmt
);
888 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
889 "fetch mode requires the object parameter");
890 } else if (!_argv
[0].isObject()) {
891 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
892 "object must be an object");
898 stmt
->fetch
.into
= _argv
[0];
903 pdo_raise_impl_error(stmt
->dbh
, stmt
, "22003",
904 "Invalid fetch mode specified");
908 stmt
->default_fetch_type
= (PDOFetchType
)mode
;
912 * PDO error (if any) has already been raised at this point.
914 * The error_code is cleared, otherwise the caller will read the
915 * last error message from the driver.
918 setPDOErrorNone(stmt
->error_code
);
922 ///////////////////////////////////////////////////////////////////////////////
923 // forward declarations
925 static bool HHVM_METHOD(PDO
, setattribute
, int64_t attribute
,
926 const Variant
& value
);
928 ///////////////////////////////////////////////////////////////////////////////
932 thread_local
std::unordered_map
<std::string
,sp_PDOConnection
> s_connections
;
935 const StaticString
s_PDO("PDO");
937 static void HHVM_METHOD(PDO
, __construct
, const String
& dsn
,
938 const String
& username
/* = null_string */,
939 const String
& password
/* = null_string */,
940 const Variant
& optionsV
/* = null_array */) {
941 auto data
= Native::data
<PDOData
>(this_
);
942 auto options
= optionsV
.isNull() ? null_array
: optionsV
.toArray();
944 String data_source
= dsn
;
946 /* parse the data source name */
947 const char *colon
= strchr(data_source
.data(), ':');
949 /* let's see if this string has a matching dsn in the php.ini */
950 String name
= "pdo.dsn."; name
+= data_source
;
952 if (!IniSetting::Get(name
, ini_dsn
)) {
953 throw_pdo_exception(uninit_null(), uninit_null(),
954 "invalid data source name");
956 data_source
= ini_dsn
;
957 colon
= strchr(data_source
.data(), ':');
959 throw_pdo_exception(uninit_null(), uninit_null(),
960 "invalid data source name (via INI: %s)",
965 if (!strncmp(data_source
.data(), "uri:", 4)) {
966 /* the specified URI holds connection details */
967 auto file
= File::Open(data_source
.substr(4), "rb");
968 if (!file
|| file
->isInvalid()) {
969 throw_pdo_exception(uninit_null(), uninit_null(),
970 "invalid data source URI");
972 data_source
= file
->readLine(1024);
973 colon
= strchr(data_source
.data(), ':');
975 throw_pdo_exception(uninit_null(), uninit_null(),
976 "invalid data source name (via URI)");
980 const PDODriverMap
&drivers
= PDODriver::GetDrivers();
981 String name
= data_source
.substr(0, colon
- data_source
.data());
982 PDODriverMap::const_iterator iter
= drivers
.find(name
.data());
983 if (iter
== drivers
.end()) {
984 /* NB: don't want to include the data_source in the error message as
985 * it might contain a password */
986 throw_pdo_exception(uninit_null(), uninit_null(), "could not find driver");
988 PDODriver
*driver
= iter
->second
;
990 /* is this supposed to be a persistent connection ? */
991 bool is_persistent
= false;
992 bool call_factory
= true;
993 std::string shashkey
;
994 if (!options
.empty()) {
995 StringBuffer hashkey
;
996 if (options
.exists(PDO_ATTR_PERSISTENT
)) {
997 Variant v
= options
[PDO_ATTR_PERSISTENT
];
998 String sv
= v
.toString();
999 if (v
.isString() && !sv
.isNumeric() && !sv
.empty()) {
1000 /* user specified key */
1001 hashkey
.printf("PDO:DBH:DSN=%s:%s:%s:%s",
1002 data_source
.data(), username
.data(),
1003 password
.data(), sv
.data());
1004 is_persistent
= true;
1006 is_persistent
= v
.toInt64();
1007 hashkey
.printf("PDO:DBH:DSN=%s:%s:%s",
1008 data_source
.data(), username
.data(),
1013 if (is_persistent
) {
1014 shashkey
= hashkey
.detach().toCppString();
1016 /* let's see if we have one cached.... */
1017 if (s_connections
.count(shashkey
)) {
1018 auto const conn
= s_connections
[shashkey
];
1019 data
->m_dbh
= driver
->createResource(conn
);
1021 /* is the connection still alive ? */
1022 if (conn
->support(PDOConnection::MethodCheckLiveness
) &&
1023 !conn
->checkLiveness()) {
1024 /* nope... need to kill it */
1025 data
->m_dbh
= nullptr;
1030 call_factory
= false;
1032 /* need a brand new pdbh */
1033 data
->m_dbh
= driver
->createResource(colon
+ 1, username
,
1036 throw_pdo_exception(uninit_null(), uninit_null(),
1037 "unable to create a connection");
1039 data
->m_dbh
->conn()->persistent_id
= shashkey
;
1044 data
->m_dbh
= driver
->createResource(colon
+ 1, username
,
1047 throw_pdo_exception(uninit_null(), uninit_null(),
1048 "unable to create a connection");
1053 data
->m_dbh
->conn()->default_fetch_type
= PDO_FETCH_BOTH
;
1056 data
->m_dbh
->conn()->auto_commit
=
1057 pdo_attr_lval(options
, PDO_ATTR_AUTOCOMMIT
, 1);
1059 if (!call_factory
) {
1060 /* we got a persistent guy from our cache */
1061 for (ArrayIter
iter(options
); iter
; ++iter
) {
1062 HHVM_MN(PDO
, setattribute
)(this_
, iter
.first().toInt64(),
1065 } else if (data
->m_dbh
) {
1066 if (is_persistent
) {
1067 assert(!shashkey
.empty());
1068 s_connections
[shashkey
] = data
->m_dbh
->conn();
1071 data
->m_dbh
->conn()->driver
= driver
;
1072 for (ArrayIter
iter(options
); iter
; ++iter
) {
1073 HHVM_MN(PDO
, setattribute
)(this_
, iter
.first().toInt64(),
1079 static Variant
HHVM_METHOD(PDO
, prepare
, const String
& statement
,
1080 const Array
& options
= null_array
) {
1081 auto data
= Native::data
<PDOData
>(this_
);
1083 assert(data
->m_dbh
->conn()->driver
);
1084 setPDOErrorNone(data
->m_dbh
->conn()->error_code
);
1085 data
->m_dbh
->query_stmt
= nullptr;
1089 if (options
.exists(PDO_ATTR_STATEMENT_CLASS
)) {
1090 Variant opt
= options
[PDO_ATTR_STATEMENT_CLASS
];
1091 if (!valid_statement_class(data
->m_dbh
, opt
, clsname
, ctor_args
)) {
1095 clsname
= data
->m_dbh
->conn()->def_stmt_clsname
;
1096 ctor_args
= data
->m_dbh
->def_stmt_ctor_args
;
1099 Object ret
= pdo_stmt_instantiate(data
->m_dbh
, clsname
, ctor_args
);
1101 pdo_raise_impl_error
1102 (data
->m_dbh
, nullptr, "HY000",
1103 "failed to instantiate user-supplied statement class");
1104 PDO_HANDLE_DBH_ERR(data
->m_dbh
);
1107 PDOStatementData
*pdostmt
= Native::data
<PDOStatementData
>(ret
);
1109 if (data
->m_dbh
->conn()->preparer(statement
, &pdostmt
->m_stmt
, options
)) {
1110 auto stmt
= pdostmt
->m_stmt
;
1113 /* unconditionally keep this for later reference */
1114 stmt
->query_string
= statement
;
1115 stmt
->default_fetch_type
= data
->m_dbh
->conn()->default_fetch_type
;
1116 stmt
->dbh
= data
->m_dbh
;
1118 pdo_stmt_construct(stmt
, ret
, clsname
, ctor_args
);
1122 PDO_HANDLE_DBH_ERR(data
->m_dbh
);
1126 static bool HHVM_METHOD(PDO
, begintransaction
) {
1127 auto data
= Native::data
<PDOData
>(this_
);
1129 if (data
->m_dbh
->conn()->in_txn
) {
1130 throw_pdo_exception(uninit_null(), uninit_null(),
1131 "There is already an active transaction");
1133 if (data
->m_dbh
->conn()->begin()) {
1134 data
->m_dbh
->conn()->in_txn
= 1;
1137 if (strcmp(data
->m_dbh
->conn()->error_code
, PDO_ERR_NONE
)) {
1138 pdo_handle_error(data
->m_dbh
, nullptr);
1143 static bool HHVM_METHOD(PDO
, commit
) {
1144 auto data
= Native::data
<PDOData
>(this_
);
1146 assert(data
->m_dbh
->conn()->driver
);
1147 if (!data
->m_dbh
->conn()->in_txn
) {
1148 throw_pdo_exception(uninit_null(), uninit_null(),
1149 "There is no active transaction");
1151 if (data
->m_dbh
->conn()->commit()) {
1152 data
->m_dbh
->conn()->in_txn
= 0;
1155 PDO_HANDLE_DBH_ERR(data
->m_dbh
);
1159 static bool HHVM_METHOD(PDO
, intransaction
) {
1160 auto data
= Native::data
<PDOData
>(this_
);
1162 assert(data
->m_dbh
->conn()->driver
);
1163 return data
->m_dbh
->conn()->in_txn
;
1166 static bool HHVM_METHOD(PDO
, rollback
) {
1167 auto data
= Native::data
<PDOData
>(this_
);
1169 assert(data
->m_dbh
->conn()->driver
);
1170 if (!data
->m_dbh
->conn()->in_txn
) {
1171 throw_pdo_exception(uninit_null(), uninit_null(),
1172 "There is no active transaction");
1174 if (data
->m_dbh
->conn()->rollback()) {
1175 data
->m_dbh
->conn()->in_txn
= 0;
1178 PDO_HANDLE_DBH_ERR(data
->m_dbh
);
1182 static bool HHVM_METHOD(PDO
, setattribute
, int64_t attribute
,
1183 const Variant
& value
) {
1184 auto data
= Native::data
<PDOData
>(this_
);
1186 assert(data
->m_dbh
->conn()->driver
);
1188 #define PDO_LONG_PARAM_CHECK \
1189 if (!value.isInteger() && !value.isString() && !value.isBoolean()) { \
1190 pdo_raise_impl_error(data->m_dbh, nullptr, "HY000", \
1191 "attribute value must be an integer"); \
1192 PDO_HANDLE_DBH_ERR(data->m_dbh); \
1196 switch (attribute) {
1197 case PDO_ATTR_ERRMODE
:
1198 PDO_LONG_PARAM_CHECK
;
1199 switch (value
.toInt64()) {
1200 case PDO_ERRMODE_SILENT
:
1201 case PDO_ERRMODE_WARNING
:
1202 case PDO_ERRMODE_EXCEPTION
:
1203 data
->m_dbh
->conn()->error_mode
= (PDOErrorMode
)value
.toInt64();
1206 pdo_raise_impl_error(data
->m_dbh
, nullptr, "HY000", "invalid error mode");
1207 PDO_HANDLE_DBH_ERR(data
->m_dbh
);
1213 PDO_LONG_PARAM_CHECK
;
1214 switch (value
.toInt64()) {
1215 case PDO_CASE_NATURAL
:
1216 case PDO_CASE_UPPER
:
1217 case PDO_CASE_LOWER
:
1218 data
->m_dbh
->conn()->desired_case
= (PDOCaseConversion
)value
.toInt64();
1221 pdo_raise_impl_error(data
->m_dbh
, nullptr, "HY000",
1222 "invalid case folding mode");
1223 PDO_HANDLE_DBH_ERR(data
->m_dbh
);
1228 case PDO_ATTR_ORACLE_NULLS
:
1229 PDO_LONG_PARAM_CHECK
;
1230 data
->m_dbh
->conn()->oracle_nulls
= value
.toInt64();
1233 case PDO_ATTR_DEFAULT_FETCH_MODE
:
1234 if (value
.isArray()) {
1235 if (value
.toCArrRef().exists(0)) {
1236 Variant tmp
= value
.toCArrRef()[0];
1237 if (tmp
.isInteger() && ((tmp
.toInt64() == PDO_FETCH_INTO
||
1238 tmp
.toInt64() == PDO_FETCH_CLASS
))) {
1239 pdo_raise_impl_error(data
->m_dbh
, nullptr, "HY000",
1240 "FETCH_INTO and FETCH_CLASS are not yet "
1241 "supported as default fetch modes");
1246 PDO_LONG_PARAM_CHECK
;
1248 if (value
.toInt64() == PDO_FETCH_USE_DEFAULT
) {
1249 pdo_raise_impl_error(data
->m_dbh
, nullptr,
1250 "HY000", "invalid fetch mode type");
1253 data
->m_dbh
->conn()->default_fetch_type
= (PDOFetchType
)value
.toInt64();
1256 case PDO_ATTR_STRINGIFY_FETCHES
:
1257 PDO_LONG_PARAM_CHECK
;
1258 data
->m_dbh
->conn()->stringify
= value
.toInt64() ? 1 : 0;
1261 case PDO_ATTR_STATEMENT_CLASS
:
1263 if (data
->m_dbh
->conn()->is_persistent
) {
1264 pdo_raise_impl_error(data
->m_dbh
, nullptr, "HY000",
1265 "PDO::ATTR_STATEMENT_CLASS cannot be used "
1266 "with persistent PDO instances");
1267 PDO_HANDLE_DBH_ERR(data
->m_dbh
);
1271 if (!valid_statement_class(data
->m_dbh
, value
, clsname
,
1272 data
->m_dbh
->def_stmt_ctor_args
)) {
1275 data
->m_dbh
->conn()->def_stmt_clsname
= clsname
.c_str();
1280 if (data
->m_dbh
->conn()->support(PDOConnection::MethodSetAttribute
)) {
1281 setPDOErrorNone(data
->m_dbh
->conn()->error_code
);
1282 data
->m_dbh
->query_stmt
= nullptr;
1283 if (data
->m_dbh
->conn()->setAttribute(attribute
, value
)) {
1288 if (attribute
== PDO_ATTR_AUTOCOMMIT
) {
1289 throw_pdo_exception(uninit_null(), uninit_null(),
1290 "The auto-commit mode cannot be changed for this "
1292 } else if (!data
->m_dbh
->conn()->support(PDOConnection::MethodSetAttribute
)) {
1293 pdo_raise_impl_error(data
->m_dbh
, nullptr, "IM001",
1294 "driver does not support setting attributes");
1296 PDO_HANDLE_DBH_ERR(data
->m_dbh
);
1301 static Variant
HHVM_METHOD(PDO
, getattribute
, int64_t attribute
) {
1302 auto data
= Native::data
<PDOData
>(this_
);
1304 assert(data
->m_dbh
->conn()->driver
);
1305 setPDOErrorNone(data
->m_dbh
->conn()->error_code
);
1306 data
->m_dbh
->query_stmt
= nullptr;
1308 /* handle generic PDO-level attributes */
1309 switch (attribute
) {
1310 case PDO_ATTR_PERSISTENT
:
1311 return (bool)data
->m_dbh
->conn()->is_persistent
;
1314 return (int64_t)data
->m_dbh
->conn()->desired_case
;
1316 case PDO_ATTR_ORACLE_NULLS
:
1317 return (int64_t)data
->m_dbh
->conn()->oracle_nulls
;
1319 case PDO_ATTR_ERRMODE
:
1320 return (int64_t)data
->m_dbh
->conn()->error_mode
;
1322 case PDO_ATTR_DRIVER_NAME
:
1323 return String(data
->m_dbh
->conn()->driver
->getName());
1325 case PDO_ATTR_STATEMENT_CLASS
: {
1327 ret
.append(String(data
->m_dbh
->conn()->def_stmt_clsname
));
1328 if (!data
->m_dbh
->def_stmt_ctor_args
.isNull()) {
1329 ret
.append(data
->m_dbh
->def_stmt_ctor_args
);
1333 case PDO_ATTR_DEFAULT_FETCH_MODE
:
1334 return (int64_t)data
->m_dbh
->conn()->default_fetch_type
;
1337 if (!data
->m_dbh
->conn()->support(PDOConnection::MethodGetAttribute
)) {
1338 pdo_raise_impl_error(data
->m_dbh
, nullptr, "IM001",
1339 "driver does not support getting attributes");
1344 switch (data
->m_dbh
->conn()->getAttribute(attribute
, ret
)) {
1346 PDO_HANDLE_DBH_ERR(data
->m_dbh
);
1349 pdo_raise_impl_error(data
->m_dbh
, nullptr, "IM001",
1350 "driver does not support that attribute");
1356 static Variant
HHVM_METHOD(PDO
, exec
, const String
& query
) {
1357 auto data
= Native::data
<PDOData
>(this_
);
1359 SYNC_VM_REGS_SCOPED();
1360 if (query
.empty()) {
1361 pdo_raise_impl_error(data
->m_dbh
, nullptr, "HY000",
1362 "trying to execute an empty query");
1366 assert(data
->m_dbh
->conn()->driver
);
1367 setPDOErrorNone(data
->m_dbh
->conn()->error_code
);
1368 data
->m_dbh
->query_stmt
= nullptr;
1370 int64_t ret
= data
->m_dbh
->conn()->doer(query
);
1372 PDO_HANDLE_DBH_ERR(data
->m_dbh
);
1378 static Variant
HHVM_METHOD(PDO
, lastinsertid
,
1379 const String
& seqname
/* = null_string */) {
1380 auto data
= Native::data
<PDOData
>(this_
);
1382 assert(data
->m_dbh
->conn()->driver
);
1383 setPDOErrorNone(data
->m_dbh
->conn()->error_code
);
1384 data
->m_dbh
->query_stmt
= nullptr;
1386 if (!data
->m_dbh
->conn()->support(PDOConnection::MethodLastId
)) {
1387 pdo_raise_impl_error(data
->m_dbh
, nullptr, "IM001",
1388 "driver does not support lastInsertId()");
1392 String ret
= data
->m_dbh
->conn()->lastId(seqname
.data());
1394 PDO_HANDLE_DBH_ERR(data
->m_dbh
);
1400 static Variant
HHVM_METHOD(PDO
, errorcode
) {
1401 auto data
= Native::data
<PDOData
>(this_
);
1403 assert(data
->m_dbh
->conn()->driver
);
1404 if (data
->m_dbh
->query_stmt
) {
1405 return String(data
->m_dbh
->query_stmt
->error_code
, CopyString
);
1408 if (data
->m_dbh
->conn()->error_code
[0] == '\0') {
1413 * Making sure that we fallback to the default implementation
1414 * if the dbh->error_code is not null.
1416 return String(data
->m_dbh
->conn()->error_code
, CopyString
);
1419 static Array
HHVM_METHOD(PDO
, errorinfo
) {
1420 auto data
= Native::data
<PDOData
>(this_
);
1422 assert(data
->m_dbh
->conn()->driver
);
1425 if (data
->m_dbh
->query_stmt
) {
1426 ret
.append(String(data
->m_dbh
->query_stmt
->error_code
, CopyString
));
1428 ret
.append(String(data
->m_dbh
->conn()->error_code
, CopyString
));
1431 if (data
->m_dbh
->conn()->support(PDOConnection::MethodFetchErr
)) {
1432 data
->m_dbh
->conn()->fetchErr(data
->m_dbh
->query_stmt
, ret
);
1436 * In order to be consistent, we have to make sure we add the good amount
1437 * of nulls depending on the current number of elements. We make a simple
1438 * difference and add the needed elements
1440 int error_count
= ret
.size();
1441 int error_expected_count
= 3;
1442 if (error_expected_count
> error_count
) {
1443 int error_count_diff
= error_expected_count
- error_count
;
1444 for (int i
= 0; i
< error_count_diff
; i
++) {
1445 ret
.append(uninit_null());
1451 static Variant
HHVM_METHOD(PDO
, query
, const String
& sql
,
1452 const Array
& _argv
) {
1454 auto data
= Native::data
<PDOData
>(this_
);
1455 SYNC_VM_REGS_SCOPED();
1456 assert(data
->m_dbh
->conn()->driver
);
1457 setPDOErrorNone(data
->m_dbh
->conn()->error_code
);
1458 data
->m_dbh
->query_stmt
= nullptr;
1460 Object ret
= pdo_stmt_instantiate(data
->m_dbh
,
1461 data
->m_dbh
->conn()->def_stmt_clsname
,
1462 data
->m_dbh
->def_stmt_ctor_args
);
1464 pdo_raise_impl_error
1465 (data
->m_dbh
, nullptr, "HY000",
1466 "failed to instantiate user supplied statement class");
1469 PDOStatementData
*pdostmt
= Native::data
<PDOStatementData
>(ret
);
1471 if (data
->m_dbh
->conn()->preparer(sql
, &pdostmt
->m_stmt
, Array())) {
1472 auto stmt
= pdostmt
->m_stmt
;
1475 /* unconditionally keep this for later reference */
1476 stmt
->query_string
= sql
;
1477 stmt
->default_fetch_type
= data
->m_dbh
->conn()->default_fetch_type
;
1478 stmt
->active_query_string
= stmt
->query_string
;
1479 stmt
->dbh
= data
->m_dbh
;
1480 stmt
->lazy_object_ref
.unset();
1482 setPDOErrorNone(stmt
->error_code
);
1484 // when we add support for varargs here, we only need to set the stmt if
1485 // the argument count is > 1
1486 int argc
= _argv
.size() + 1;
1488 pdo_stmt_set_fetch_mode(stmt
, 0, _argv
.rvalAt(0).toInt64Val(),
1489 HHVM_FN(array_splice
)(_argv
, 1).toArray())) {
1490 /* now execute the statement */
1491 setPDOErrorNone(stmt
->error_code
);
1492 if (stmt
->executer()) {
1494 if (!stmt
->executed
) {
1495 if (stmt
->dbh
->conn()->alloc_own_columns
) {
1496 ok
= pdo_stmt_describe_columns(stmt
);
1501 pdo_stmt_construct(stmt
, ret
, data
->m_dbh
->conn()->def_stmt_clsname
,
1502 data
->m_dbh
->def_stmt_ctor_args
);
1507 /* something broke */
1508 data
->m_dbh
->query_stmt
= stmt
.get();
1509 PDO_HANDLE_STMT_ERR(stmt
);
1511 PDO_HANDLE_DBH_ERR(data
->m_dbh
);
1517 static Variant
HHVM_METHOD(PDO
, quote
, const String
& str
,
1518 int64_t paramtype
/* = q_PDO$$PARAM_STR */) {
1519 auto data
= Native::data
<PDOData
>(this_
);
1521 assert(data
->m_dbh
->conn()->driver
);
1522 setPDOErrorNone(data
->m_dbh
->conn()->error_code
);
1523 data
->m_dbh
->query_stmt
= nullptr;
1525 if (!data
->m_dbh
->conn()->support(PDOConnection::MethodQuoter
)) {
1526 pdo_raise_impl_error(data
->m_dbh
, nullptr, "IM001",
1527 "driver does not support quoting");
1532 if (data
->m_dbh
->conn()->quoter(str
, quoted
, (PDOParamType
)paramtype
)) {
1535 PDO_HANDLE_DBH_ERR(data
->m_dbh
);
1539 static bool HHVM_METHOD(PDO
, sqlitecreatefunction
, const String
& name
,
1540 const Variant
& callback
, int64_t argcount
/* = -1 */) {
1541 #ifdef ENABLE_EXTENSION_PDO_SQLITE
1542 auto data
= Native::data
<PDOData
>(this_
);
1544 auto conn
= std::dynamic_pointer_cast
<PDOSqliteConnection
>(
1545 data
->m_dbh
->conn());
1546 if (conn
== nullptr) {
1549 return conn
->createFunction(name
, callback
, argcount
);
1551 raise_recoverable_error("PDO::sqliteCreateFunction not implemented");
1556 static bool HHVM_METHOD(PDO
, sqlitecreateaggregate
, const String
& name
,
1557 const Variant
& step
, const Variant
& final
,
1558 int64_t argcount
/* = -1 */) {
1559 raise_recoverable_error("PDO::sqliteCreateAggregate not implemented");
1563 static Variant
HHVM_METHOD(PDO
, __wakeup
) {
1564 throw_pdo_exception(uninit_null(), uninit_null(),
1565 "You cannot serialize or unserialize PDO instances");
1569 static Variant
HHVM_METHOD(PDO
, __sleep
) {
1570 throw_pdo_exception(uninit_null(), uninit_null(),
1571 "You cannot serialize or unserialize PDO instances");
1575 static Array
HHVM_STATIC_METHOD(PDO
, getAvailableDrivers
) {
1576 return f_pdo_drivers();
1579 ///////////////////////////////////////////////////////////////////////////////
1581 static inline bool rewrite_name_to_position(sp_PDOStatement stmt
,
1582 sp_PDOBoundParam param
) {
1583 if (!stmt
->bound_param_map
.empty()) {
1584 /* rewriting :name to ? style.
1585 * We need to fixup the parameter numbers on the parameters.
1586 * If we find that a given named parameter has been used twice,
1587 * we will raise an error, as we can't be sure that it is safe
1588 * to bind multiple parameters onto the same zval in the underlying
1590 if (stmt
->named_rewrite_template
) {
1591 /* this is not an error here */
1594 if (param
->name
.empty()) {
1595 /* do the reverse; map the parameter number to the name */
1596 if (stmt
->bound_param_map
.exists(param
->paramno
)) {
1597 param
->name
= stmt
->bound_param_map
[param
->paramno
].toString();
1600 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY093",
1601 "parameter was not defined");
1606 for (ArrayIter
iter(stmt
->bound_param_map
); iter
; ++iter
, ++position
) {
1607 if (iter
.second().toString() == param
->name
) {
1608 if (param
->paramno
>= 0) {
1609 pdo_raise_impl_error
1610 (stmt
->dbh
, stmt
, "IM001",
1611 "PDO refuses to handle repeating the same :named parameter "
1612 "for multiple positions with this driver, as it might be "
1613 "unsafe to do so. Consider using a separate name for each "
1614 "parameter instead");
1617 param
->paramno
= position
;
1621 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY093",
1622 "parameter was not defined");
1628 /* trigger callback hook for parameters */
1629 static bool dispatch_param_event(sp_PDOStatement stmt
,
1630 PDOParamEvent event_type
) {
1631 if (!stmt
->support(PDOStatement::MethodParamHook
)) {
1634 for (ArrayIter
iter(stmt
->bound_params
); iter
; ++iter
) {
1635 auto param
= cast
<PDOBoundParam
>(iter
.second());
1636 if (!stmt
->paramHook(param
.get(), event_type
)) {
1640 for (ArrayIter
iter(stmt
->bound_columns
); iter
; ++iter
) {
1641 auto param
= cast
<PDOBoundParam
>(iter
.second());
1642 if (!stmt
->paramHook(param
.get(), event_type
)) {
1649 static void get_lazy_object(sp_PDOStatement stmt
, Variant
&ret
) {
1650 if (stmt
->lazy_object_ref
.isNull()) {
1651 stmt
->lazy_object_ref
= stmt
;
1653 ret
= stmt
->lazy_object_ref
;
1656 static bool really_register_bound_param(sp_PDOBoundParam param
,
1657 sp_PDOStatement stmt
,
1659 Array
&hash
= is_param
? stmt
->bound_params
: stmt
->bound_columns
;
1661 if (PDO_PARAM_TYPE(param
->param_type
) == PDO_PARAM_STR
&&
1662 param
->max_value_len
<= 0 && !param
->parameter
.isNull()) {
1663 param
->parameter
= param
->parameter
.toString();
1664 } else if (PDO_PARAM_TYPE(param
->param_type
) == PDO_PARAM_INT
&&
1665 param
->parameter
.isBoolean()) {
1666 param
->parameter
= param
->parameter
.toInt64();
1667 } else if (PDO_PARAM_TYPE(param
->param_type
) == PDO_PARAM_BOOL
&&
1668 param
->parameter
.isInteger()) {
1669 param
->parameter
= param
->parameter
.toBoolean();
1671 param
->stmt
= stmt
.get();
1672 param
->is_param
= is_param
;
1674 if (!is_param
&& !param
->name
.empty() && !stmt
->columns
.empty()) {
1675 /* try to map the name to the column */
1676 for (int i
= 0; i
< stmt
->column_count
; i
++) {
1677 if (cast
<PDOColumn
>(stmt
->columns
[i
])->name
== param
->name
) {
1683 /* if you prepare and then execute passing an array of params keyed by
1684 names, then this will trigger, and we don't want that */
1685 if (param
->paramno
== -1) {
1686 raise_warning("Did not found column name '%s' in the defined columns;"
1687 " it will not be bound", param
->name
.data());
1691 if (is_param
&& !param
->name
.empty() && param
->name
[0] != ':') {
1692 param
->name
= String(":") + param
->name
;
1695 if (is_param
&& !rewrite_name_to_position(stmt
, param
)) {
1696 param
->name
.reset();
1700 /* ask the driver to perform any normalization it needs on the
1701 * parameter name. Note that it is illegal for the driver to take
1702 * a reference to param, as it resides in transient storage only
1704 if (stmt
->support(PDOStatement::MethodParamHook
)) {
1705 if (!stmt
->paramHook(param
.get(), PDO_PARAM_EVT_NORMALIZE
)) {
1706 param
->name
.reset();
1711 /* delete any other parameter registered with this number.
1712 * If the parameter is named, it will be removed and correctly
1713 * disposed of by the hash_update call that follows */
1714 if (param
->paramno
>= 0) {
1715 hash
.remove(param
->paramno
);
1718 /* allocate storage for the parameter, keyed by its "canonical" name */
1719 if (!param
->name
.empty()) {
1720 hash
.set(param
->name
, Variant(param
));
1722 hash
.set(param
->paramno
, Variant(param
));
1725 /* tell the driver we just created a parameter */
1726 if (stmt
->support(PDOStatement::MethodParamHook
)) {
1727 if (!stmt
->paramHook(param
.get(), PDO_PARAM_EVT_ALLOC
)) {
1728 /* undo storage allocation; the hash will free the parameter
1729 * name if required */
1730 if (!param
->name
.empty()) {
1731 hash
.remove(param
->name
);
1733 hash
.remove(param
->paramno
);
1735 param
->parameter
.unset();
1742 static inline void fetch_value(sp_PDOStatement stmt
, Variant
&dest
, int colno
,
1743 int *type_override
) {
1744 if (colno
< 0 || colno
>= stmt
->column_count
) {
1747 auto col
= cast
<PDOColumn
>(stmt
->columns
[colno
]);
1748 int type
= PDO_PARAM_TYPE(col
->param_type
);
1749 int new_type
= type_override
? PDO_PARAM_TYPE(*type_override
) : type
;
1751 stmt
->getColumn(colno
, dest
);
1753 if (type
!= new_type
) {
1755 case PDO_PARAM_INT
: dest
= dest
.toInt64(); break;
1756 case PDO_PARAM_BOOL
: dest
= dest
.toBoolean(); break;
1757 case PDO_PARAM_STR
: dest
= dest
.toString(); break;
1758 case PDO_PARAM_NULL
: dest
= init_null(); break;
1761 if (stmt
->dbh
->conn()->stringify
&& (dest
.isInteger() || dest
.isDouble())) {
1762 dest
= dest
.toString();
1764 if (dest
.isNull() && stmt
->dbh
->conn()->oracle_nulls
== PDO_NULL_TO_STRING
) {
1765 dest
= empty_string_variant();
1769 static bool do_fetch_common(sp_PDOStatement stmt
, PDOFetchOrientation ori
,
1770 long offset
, bool do_bind
) {
1771 if (!stmt
->executed
) {
1774 if (!dispatch_param_event(stmt
, PDO_PARAM_EVT_FETCH_PRE
)) {
1777 if (!stmt
->fetcher(ori
, offset
)) {
1780 /* some drivers might need to describe the columns now */
1781 if (stmt
->columns
.empty() && !pdo_stmt_describe_columns(stmt
)) {
1784 if (!dispatch_param_event(stmt
, PDO_PARAM_EVT_FETCH_POST
)) {
1788 if (do_bind
&& !stmt
->bound_columns
.empty()) {
1789 /* update those bound column variables now */
1790 for (ArrayIter
iter(stmt
->bound_columns
); iter
; ++iter
) {
1791 auto param
= cast
<PDOBoundParam
>(iter
.second());
1792 if (param
->paramno
>= 0) {
1793 param
->parameter
.setNull();
1795 fetch_value(stmt
, param
->parameter
, param
->paramno
,
1796 (int *)¶m
->param_type
);
1797 /* TODO: some smart thing that avoids duplicating the value in the
1798 * general loop below. For now, if you're binding output columns,
1799 * it's better to use LAZY or BOUND fetches if you want to shave
1800 * off those cycles */
1808 static bool do_fetch_func_prepare(sp_PDOStatement stmt
) {
1809 if (!is_callable(stmt
->fetch
.func
)) {
1810 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
1811 "user-supplied function must be a valid callback");
1817 /* perform a fetch. If do_bind is true, update any bound columns.
1818 * If return_value is not null, store values into it according to HOW. */
1819 static bool do_fetch(sp_PDOStatement stmt
,
1823 PDOFetchOrientation ori
,
1825 Variant
*return_all
) {
1826 if (how
== PDO_FETCH_USE_DEFAULT
) {
1827 how
= stmt
->default_fetch_type
;
1829 int flags
= how
& PDO_FETCH_FLAGS
;
1830 how
= (PDOFetchType
)(how
& ~PDO_FETCH_FLAGS
);
1832 if (!do_fetch_common(stmt
, ori
, offset
, do_bind
)) {
1836 if (how
== PDO_FETCH_BOUND
) {
1842 if ((flags
& PDO_FETCH_GROUP
) && stmt
->fetch
.column
== -1) {
1845 colno
= stmt
->fetch
.column
;
1848 if (how
== PDO_FETCH_LAZY
) {
1849 get_lazy_object(stmt
, ret
);
1853 String clsname
, old_clsname
;
1854 Variant old_ctor_args
;
1858 case PDO_FETCH_USE_DEFAULT
:
1859 case PDO_FETCH_ASSOC
:
1860 case PDO_FETCH_BOTH
:
1862 case PDO_FETCH_NAMED
:
1863 ret
= Array::Create();
1866 case PDO_FETCH_KEY_PAIR
:
1867 if (stmt
->column_count
!= 2) {
1868 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
1869 "PDO::FETCH_KEY_PAIR fetch mode requires the "
1870 "result set to contain extactly 2 columns.");
1874 ret
= Array::Create();
1878 case PDO_FETCH_COLUMN
:
1879 if (colno
>= 0 && colno
< stmt
->column_count
) {
1880 if (flags
== PDO_FETCH_GROUP
&& stmt
->fetch
.column
== -1) {
1881 fetch_value(stmt
, ret
, 1, NULL
);
1882 } else if (flags
== PDO_FETCH_GROUP
&& colno
) {
1883 fetch_value(stmt
, ret
, 0, NULL
);
1885 fetch_value(stmt
, ret
, colno
, NULL
);
1892 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000", "Invalid column index");
1897 ret
= SystemLib::AllocStdClassObject();
1900 case PDO_FETCH_CLASS
:
1901 if (flags
& PDO_FETCH_CLASSTYPE
) {
1902 old_clsname
= stmt
->fetch
.clsname
;
1903 old_ctor_args
= stmt
->fetch
.ctor_args
;
1906 fetch_value(stmt
, val
, i
++, NULL
);
1907 if (!val
.isNull()) {
1908 if (!HHVM_FN(class_exists
)(val
.toString())) {
1909 stmt
->fetch
.clsname
= "stdclass";
1911 stmt
->fetch
.clsname
= val
.toString();
1915 do_fetch_class_prepare(stmt
);
1917 clsname
= stmt
->fetch
.clsname
;
1918 if (clsname
.empty()) {
1919 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
1920 "No fetch class specified");
1923 if ((flags
& PDO_FETCH_SERIALIZE
) == 0) {
1924 ret
= create_object_only(clsname
);
1925 if (!do_fetch_class_prepare(stmt
)) {
1928 if (!stmt
->fetch
.constructor
.empty() &&
1929 (flags
& PDO_FETCH_PROPS_LATE
)) {
1930 ret
.asCObjRef()->o_invoke(stmt
->fetch
.constructor
,
1931 stmt
->fetch
.ctor_args
.toArray());
1932 ret
.asCObjRef()->clearNoDestruct();
1937 case PDO_FETCH_INTO
:
1938 if (stmt
->fetch
.into
.isNull()) {
1939 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
1940 "No fetch-into object specified.");
1944 ret
= stmt
->fetch
.into
;
1945 if (ret
.isObject() &&
1946 ret
.getObjectData()->instanceof(SystemLib::s_stdclassClass
)) {
1947 how
= PDO_FETCH_OBJ
;
1951 case PDO_FETCH_FUNC
:
1952 if (stmt
->fetch
.func
.empty()) {
1953 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
1954 "No fetch function specified");
1957 if (!do_fetch_func_prepare(stmt
)) {
1968 if (return_all
&& how
!= PDO_FETCH_KEY_PAIR
) {
1969 if (flags
== PDO_FETCH_GROUP
&& how
== PDO_FETCH_COLUMN
&&
1970 stmt
->fetch
.column
> 0) {
1971 fetch_value(stmt
, grp_val
, colno
, NULL
);
1973 fetch_value(stmt
, grp_val
, i
, NULL
);
1975 grp_val
= grp_val
.toString();
1976 if (how
== PDO_FETCH_COLUMN
) {
1977 i
= stmt
->column_count
; /* no more data to fetch */
1983 for (int idx
= 0; i
< stmt
->column_count
; i
++, idx
++) {
1984 const String
& name
= cast
<PDOColumn
>(stmt
->columns
[i
])->name
;
1986 fetch_value(stmt
, val
, i
, NULL
);
1989 case PDO_FETCH_ASSOC
:
1990 ret
.toArrRef().set(name
, val
);
1993 case PDO_FETCH_KEY_PAIR
: {
1995 fetch_value(stmt
, tmp
, ++i
, NULL
);
1997 return_all
->toArrRef().set(val
, tmp
);
1999 ret
.toArrRef().set(val
, tmp
);
2003 case PDO_FETCH_USE_DEFAULT
:
2004 case PDO_FETCH_BOTH
:
2005 ret
.toArrRef().set(name
, val
);
2006 ret
.toArrRef().append(val
);
2009 case PDO_FETCH_NAMED
: {
2010 /* already have an item with this name? */
2012 if (ret
.toArrRef().exists(name
)) {
2013 auto& curr_val
= ret
.toArrRef().lvalAt(name
);
2014 if (!curr_val
.isArray()) {
2015 Array arr
= Array::Create();
2016 arr
.append(curr_val
);
2018 ret
.toArray().set(name
, arr
);
2020 curr_val
.toArrRef().append(val
);
2023 ret
.toArrRef().set(name
, val
);
2028 ret
.toArrRef().append(val
);
2032 case PDO_FETCH_INTO
:
2033 ret
.toObject()->o_set(name
, val
);
2036 case PDO_FETCH_CLASS
:
2037 if ((flags
& PDO_FETCH_SERIALIZE
) == 0 || idx
) {
2038 ret
.toObject()->o_set(name
, val
);
2041 ret
= unserialize_from_string(val
);
2042 if (same(ret
, false)) {
2043 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
2044 "cannot unserialize data");
2048 // hzhao: not sure how we support class serialization
2049 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY000",
2050 "cannot unserialize class");
2055 case PDO_FETCH_FUNC
:
2056 forceToArray(stmt
->fetch
.values
).set(idx
, val
);
2060 pdo_raise_impl_error(stmt
->dbh
, stmt
, "22003", "mode is out of range");
2066 case PDO_FETCH_CLASS
:
2067 if (!stmt
->fetch
.constructor
.empty() &&
2068 !(flags
& (PDO_FETCH_PROPS_LATE
| PDO_FETCH_SERIALIZE
))) {
2069 ret
.toObject()->o_invoke(stmt
->fetch
.constructor
,
2070 stmt
->fetch
.ctor_args
.toArray());
2071 ret
.toObject()->clearNoDestruct();
2073 if (flags
& PDO_FETCH_CLASSTYPE
) {
2074 stmt
->fetch
.clsname
= old_clsname
;
2075 stmt
->fetch
.ctor_args
= old_ctor_args
;
2079 case PDO_FETCH_FUNC
:
2080 ret
= vm_call_user_func(stmt
->fetch
.func
,
2081 stmt
->fetch
.values
.toArray());
2089 if ((flags
& PDO_FETCH_UNIQUE
) == PDO_FETCH_UNIQUE
) {
2090 return_all
->toArrRef().set(grp_val
, ret
);
2092 auto& lval
= return_all
->toArrRef().lvalAt(grp_val
);
2093 forceToArray(lval
).append(ret
);
2100 static int register_bound_param(const Variant
& paramno
, VRefParam param
,
2101 int64_t type
, int64_t max_value_len
,
2102 const Variant
& driver_params
,
2103 sp_PDOStatement stmt
, bool is_param
) {
2104 auto p
= req::make
<PDOBoundParam
>();
2105 // need to make sure this is NULL, in case a fatal errors occurs before it's
2106 // set inside really_register_bound_param
2109 if (paramno
.isNumeric()) {
2110 p
->paramno
= paramno
.toInt64();
2113 p
->name
= paramno
.toString();
2116 p
->parameter
.setWithRef(param
);
2117 p
->param_type
= (PDOParamType
)type
;
2118 p
->max_value_len
= max_value_len
;
2119 p
->driver_params
= driver_params
;
2121 if (p
->paramno
> 0) {
2122 --p
->paramno
; /* make it zero-based internally */
2123 } else if (p
->name
.empty()) {
2124 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY093",
2125 "Columns/Parameters are 1-based");
2129 if (!really_register_bound_param(p
, stmt
, is_param
)) {
2130 p
->parameter
.unset();
2136 static bool generic_stmt_attr_get(sp_PDOStatement stmt
, Variant
&ret
,
2138 if (attr
== PDO_ATTR_EMULATE_PREPARES
) {
2139 ret
= (bool)(stmt
->supports_placeholders
== PDO_PLACEHOLDER_NONE
);
2145 ///////////////////////////////////////////////////////////////////////////////
2148 #define PDO_PARSER_TEXT 1
2149 #define PDO_PARSER_BIND 2
2150 #define PDO_PARSER_BIND_POS 3
2151 #define PDO_PARSER_EOI 4
2153 #define RET(i) {s->cur = cursor; return i; }
2154 #define SKIP_ONE(i) {s->cur = s->tok + 1; return 1; }
2156 #define YYCTYPE unsigned char
2157 #define YYCURSOR cursor
2158 #define YYLIMIT limit
2159 #define YYMARKER s->ptr
2160 #define YYFILL(n) RET(PDO_PARSER_EOI)
2162 typedef struct Scanner
{
2163 char *ptr
, *cur
, *lim
, *tok
;
2166 static int scan(Scanner
*s
) {
2167 char* cursor
= s
->cur
;
2168 char* limit
= s
->lim
;
2174 if ((YYLIMIT
- YYCURSOR
) < 2) { YYFILL(2); }
2177 case 0x00: goto yy11
;
2179 case '\'': goto yy4
;
2185 yych
= *(YYMARKER
= ++YYCURSOR
);
2186 if (yych
>= 0x01) goto yy26
;
2188 { SKIP_ONE(PDO_PARSER_TEXT
); }
2190 yych
= *(YYMARKER
= ++YYCURSOR
);
2191 if (yych
<= 0x00) goto yy3
;
2258 case 'z': goto yy16
;
2260 case '?': goto yy13
;
2265 switch ((yych
= *YYCURSOR
)) {
2267 case '?': goto yy13
;
2271 { RET(PDO_PARSER_BIND_POS
); }
2274 if (YYLIMIT
<= YYCURSOR
) { YYFILL(1); }
2281 case '?': goto yy10
;
2285 { RET(PDO_PARSER_TEXT
); }
2288 { RET(PDO_PARSER_EOI
); }
2291 if (YYLIMIT
<= YYCURSOR
) { YYFILL(1); }
2295 case '?': goto yy13
;
2299 { RET(PDO_PARSER_TEXT
); }
2302 if (YYLIMIT
<= YYCURSOR
) { YYFILL(1); }
2367 case 'z': goto yy16
;
2371 { RET(PDO_PARSER_BIND
); }
2374 if (YYLIMIT
<= YYCURSOR
) { YYFILL(1); }
2378 case 0x00: goto yy21
;
2379 case '\'': goto yy23
;
2380 case '\\': goto yy22
;
2384 YYCURSOR
= YYMARKER
;
2388 if (YYLIMIT
<= YYCURSOR
) { YYFILL(1); }
2390 if (yych
<= 0x00) goto yy21
;
2394 { RET(PDO_PARSER_TEXT
); }
2397 if (YYLIMIT
<= YYCURSOR
) { YYFILL(1); }
2401 case 0x00: goto yy21
;
2402 case '"': goto yy28
;
2403 case '\\': goto yy27
;
2408 if (YYLIMIT
<= YYCURSOR
) { YYFILL(1); }
2410 if (yych
<= 0x00) goto yy21
;
2414 { RET(PDO_PARSER_TEXT
); }
2419 struct placeholder
{
2423 String quoted
; /* quoted value */
2424 struct placeholder
*next
;
2427 int pdo_parse_params(sp_PDOStatement stmt
, const String
& in
, String
&out
) {
2436 req::ptr
<PDOBoundParam
> param
;
2437 int query_type
= PDO_PLACEHOLDER_NONE
;
2438 struct placeholder
*placeholders
= NULL
, *placetail
= NULL
, *plc
= NULL
;
2440 s
.cur
= (char*)in
.data();
2441 s
.lim
= (char*)in
.data() + in
.size() + 1;
2443 /* phase 1: look for args */
2444 while ((t
= scan(&s
)) != PDO_PARSER_EOI
) {
2445 if (t
== PDO_PARSER_BIND
|| t
== PDO_PARSER_BIND_POS
) {
2446 if (t
== PDO_PARSER_BIND
) {
2447 int len
= s
.cur
- s
.tok
;
2448 if ((in
.data() < (s
.cur
- len
)) && isalnum(*(s
.cur
- len
- 1))) {
2451 query_type
|= PDO_PLACEHOLDER_NAMED
;
2453 query_type
|= PDO_PLACEHOLDER_POSITIONAL
;
2456 plc
= (placeholder
*)req::malloc(sizeof(*plc
));
2457 memset(plc
, 0, sizeof(*plc
));
2460 plc
->len
= s
.cur
- s
.tok
;
2461 plc
->bindno
= bindno
++;
2464 placetail
->next
= plc
;
2473 /* nothing to do; good! */
2477 /* did the query make sense to me? */
2478 if (query_type
== (PDO_PLACEHOLDER_NAMED
|PDO_PLACEHOLDER_POSITIONAL
)) {
2479 /* they mixed both types; punt */
2480 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY093",
2481 "mixed named and positional parameters");
2486 if ((int)stmt
->supports_placeholders
== query_type
&&
2487 !stmt
->named_rewrite_template
) {
2488 /* query matches native syntax */
2493 if (stmt
->named_rewrite_template
) {
2495 * We we pretend that the query was positional even if
2496 * it was named so that we fall into the
2497 * named rewrite case below. Not too pretty,
2499 query_type
= PDO_PLACEHOLDER_POSITIONAL
;
2502 params
= stmt
->bound_params
;
2504 /* Do we have placeholders but no bound params */
2505 if (bindno
&& params
.empty() &&
2506 stmt
->supports_placeholders
== PDO_PLACEHOLDER_NONE
) {
2507 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY093", "no parameters were bound");
2512 if (!params
.empty() && bindno
!= params
.size() &&
2513 stmt
->supports_placeholders
== PDO_PLACEHOLDER_NONE
) {
2514 /* extra bit of validation for instances when same params are bound
2516 if (query_type
!= PDO_PLACEHOLDER_POSITIONAL
&& bindno
> params
.size()) {
2518 for (plc
= placeholders
; plc
; plc
= plc
->next
) {
2519 if (!params
.exists(String(plc
->pos
, plc
->len
, CopyString
))) {
2528 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY093",
2529 "number of bound variables does not match number "
2535 /* what are we going to do ? */
2536 if (stmt
->supports_placeholders
== PDO_PLACEHOLDER_NONE
) {
2537 /* query generation */
2539 newbuffer_len
= in
.size();
2541 /* let's quote all the values */
2542 for (plc
= placeholders
; plc
; plc
= plc
->next
) {
2544 if (query_type
== PDO_PLACEHOLDER_POSITIONAL
) {
2545 vparam
= params
[plc
->bindno
];
2547 vparam
= params
[String(plc
->pos
, plc
->len
, CopyString
)];
2549 if (vparam
.isNull()) {
2550 /* parameter was not defined */
2552 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY093",
2553 "parameter was not defined");
2556 param
= cast
<PDOBoundParam
>(vparam
);
2557 if (stmt
->dbh
->conn()->support(PDOConnection::MethodQuoter
)) {
2558 if (param
->param_type
== PDO_PARAM_LOB
&&
2559 param
->parameter
.isResource()) {
2560 Variant buf
= HHVM_FN(stream_get_contents
)(
2561 param
->parameter
.toResource());
2562 if (!same(buf
, false)) {
2563 if (!stmt
->dbh
->conn()->quoter(buf
.toString(), plc
->quoted
,
2564 param
->param_type
)) {
2567 setPDOError(stmt
->error_code
, stmt
->dbh
->conn()->error_code
);
2571 pdo_raise_impl_error(stmt
->dbh
, stmt
, "HY105",
2572 "Expected a stream resource");
2578 switch (param
->parameter
.getType()) {
2581 plc
->quoted
= "NULL";
2586 plc
->quoted
= param
->parameter
.toString();
2590 param
->parameter
= param
->parameter
.toInt64();
2592 case KindOfPersistentString
:
2594 case KindOfPersistentArray
:
2597 case KindOfResource
:
2599 if (!stmt
->dbh
->conn()->quoter(
2600 param
->parameter
.toString(),
2602 param
->param_type
)) {
2605 setPDOError(stmt
->error_code
, stmt
->dbh
->conn()->error_code
);
2617 plc
->quoted
= param
->parameter
;
2619 newbuffer_len
+= plc
->quoted
.size();
2623 /* allocate output buffer */
2624 out
= String(newbuffer_len
, ReserveString
);
2625 newbuffer
= out
.mutableData();
2627 /* and build the query */
2634 memcpy(newbuffer
, ptr
, t
);
2637 memcpy(newbuffer
, plc
->quoted
.data(), plc
->quoted
.size());
2638 newbuffer
+= plc
->quoted
.size();
2639 ptr
= plc
->pos
+ plc
->len
;
2644 t
= (in
.data() + in
.size()) - ptr
;
2646 memcpy(newbuffer
, ptr
, t
);
2649 out
.setSize(newbuffer
- out
.data());
2654 } else if (query_type
== PDO_PLACEHOLDER_POSITIONAL
) {
2655 /* rewrite ? to :pdoX */
2656 StringBuffer idxbuf
;
2657 const char *tmpl
= stmt
->named_rewrite_template
?
2658 stmt
->named_rewrite_template
: ":pdo%d";
2661 newbuffer_len
= in
.size();
2663 for (plc
= placeholders
; plc
; plc
= plc
->next
) {
2665 String
name(plc
->pos
, plc
->len
, CopyString
);
2667 /* check if bound parameter is already available */
2668 if (!strcmp(name
.c_str(), "?") ||
2669 !stmt
->bound_param_map
.exists(name
)) {
2670 idxbuf
.printf(tmpl
, bind_no
++);
2673 idxbuf
.append(stmt
->bound_param_map
[name
].toString());
2677 plc
->quoted
= idxbuf
.detach();
2678 newbuffer_len
+= plc
->quoted
.size();
2680 if (!skip_map
&& stmt
->named_rewrite_template
) {
2681 /* create a mapping */
2682 stmt
->bound_param_map
.set(name
, plc
->quoted
);
2685 /* map number to name */
2686 stmt
->bound_param_map
.set(plc
->bindno
, plc
->quoted
);
2692 /* rewrite :name to ? */
2694 newbuffer_len
= in
.size();
2696 for (plc
= placeholders
; plc
; plc
= plc
->next
) {
2697 String
name(plc
->pos
, plc
->len
, CopyString
);
2698 stmt
->bound_param_map
.set(plc
->bindno
, name
);
2707 while (placeholders
) {
2709 placeholders
= plc
->next
;
2710 plc
->quoted
.reset();
2717 ///////////////////////////////////////////////////////////////////////////////
2720 const StaticString
s_PDOStatement("PDOStatement");
2722 PDOStatementData::PDOStatementData() : m_rowIndex(-1) {
2725 PDOStatementData::~PDOStatementData() { }
2727 static Variant
HHVM_METHOD(PDOStatement
, execute
,
2728 const Variant
& paramsV
/* = null_array */) {
2729 auto data
= Native::data
<PDOStatementData
>(this_
);
2730 auto params
= paramsV
.isNull() ? null_array
: paramsV
.toArray();
2732 SYNC_VM_REGS_SCOPED();
2734 if (data
->m_stmt
== nullptr) {
2735 return init_null_variant
;
2738 setPDOErrorNone(data
->m_stmt
->error_code
);
2740 if (!params
.empty()) {
2741 data
->m_stmt
->bound_params
.reset();
2742 for (ArrayIter
iter(params
); iter
; ++iter
) {
2743 auto param
= req::make
<PDOBoundParam
>();
2744 param
->param_type
= PDO_PARAM_STR
;
2745 param
->parameter
= iter
.second();
2748 if (iter
.first().isString()) {
2749 param
->name
= iter
.first();
2750 param
->paramno
= -1;
2752 int64_t num_index
= iter
.first().toInt64();
2753 /* we're okay to be zero based here */
2754 if (num_index
< 0) {
2755 pdo_raise_impl_error(data
->m_stmt
->dbh
, data
->m_stmt
,
2759 param
->paramno
= num_index
;
2762 if (!really_register_bound_param(param
, data
->m_stmt
, true)) {
2769 if (PDO_PLACEHOLDER_NONE
== data
->m_stmt
->supports_placeholders
) {
2770 /* handle the emulated parameter binding, m_stmt->active_query_string
2771 holds the query with binds expanded and quoted. */
2772 ret
= pdo_parse_params(data
->m_stmt
, data
->m_stmt
->query_string
,
2773 data
->m_stmt
->active_query_string
);
2774 if (ret
== 0) { /* no changes were made */
2775 data
->m_stmt
->active_query_string
= data
->m_stmt
->query_string
;
2777 } else if (ret
== -1) {
2778 /* something broke */
2779 PDO_HANDLE_STMT_ERR(data
->m_stmt
);
2782 } else if (!dispatch_param_event(data
->m_stmt
, PDO_PARAM_EVT_EXEC_PRE
)) {
2783 PDO_HANDLE_STMT_ERR(data
->m_stmt
);
2786 if (data
->m_stmt
->executer()) {
2787 data
->m_stmt
->active_query_string
.reset();
2788 if (!data
->m_stmt
->executed
) {
2789 /* this is the first execute */
2791 if (data
->m_stmt
->dbh
->conn()->alloc_own_columns
2792 && data
->m_stmt
->columns
.empty()) {
2793 /* for "big boy" drivers, we need to allocate memory to fetch
2794 * the results into, so lets do that now */
2795 ret
= pdo_stmt_describe_columns(data
->m_stmt
);
2798 data
->m_stmt
->executed
= 1;
2801 if (ret
&& !dispatch_param_event(data
->m_stmt
, PDO_PARAM_EVT_EXEC_POST
)) {
2807 data
->m_stmt
->active_query_string
.reset();
2808 PDO_HANDLE_STMT_ERR(data
->m_stmt
);
2812 static Variant
HHVM_METHOD(PDOStatement
, fetch
, int64_t how
= 0,
2813 int64_t orientation
= q_PDO$$FETCH_ORI_NEXT
,
2814 int64_t offset
= 0) {
2815 auto data
= Native::data
<PDOStatementData
>(this_
);
2817 SYNC_VM_REGS_SCOPED();
2819 if (data
->m_stmt
== nullptr) {
2823 setPDOErrorNone(data
->m_stmt
->error_code
);
2824 if (!pdo_stmt_verify_mode(data
->m_stmt
, how
, false)) {
2829 if (!do_fetch(data
->m_stmt
, true, ret
, (PDOFetchType
)how
,
2830 (PDOFetchOrientation
)orientation
, offset
, NULL
)) {
2831 PDO_HANDLE_STMT_ERR(data
->m_stmt
);
2837 static Variant
HHVM_METHOD(PDOStatement
, fetchobject
,
2838 const String
& class_name
/* = null_string */,
2839 const Variant
& ctor_args
/* = null */) {
2840 auto data
= Native::data
<PDOStatementData
>(this_
);
2841 if (data
->m_stmt
== nullptr) {
2845 setPDOErrorNone(data
->m_stmt
->error_code
);
2846 if (!pdo_stmt_verify_mode(data
->m_stmt
, PDO_FETCH_CLASS
, false)) {
2850 String old_clsname
= data
->m_stmt
->fetch
.clsname
;
2851 Variant old_ctor_args
= data
->m_stmt
->fetch
.ctor_args
;
2854 data
->m_stmt
->fetch
.clsname
= class_name
;
2855 if (class_name
.empty()) {
2856 data
->m_stmt
->fetch
.clsname
= "stdclass";
2858 if (!HHVM_FN(class_exists
)(data
->m_stmt
->fetch
.clsname
)) {
2859 pdo_raise_impl_error(data
->m_stmt
->dbh
, data
->m_stmt
, "HY000",
2860 "Could not find user-supplied class");
2863 if (!ctor_args
.isNull() && !ctor_args
.isArray()) {
2864 pdo_raise_impl_error(data
->m_stmt
->dbh
, data
->m_stmt
, "HY000",
2865 "ctor_args must be either NULL or an array");
2868 data
->m_stmt
->fetch
.ctor_args
= ctor_args
;
2871 if (!error
&& !do_fetch(data
->m_stmt
, true, ret
, PDO_FETCH_CLASS
,
2872 PDO_FETCH_ORI_NEXT
, 0, NULL
)) {
2876 PDO_HANDLE_STMT_ERR(data
->m_stmt
);
2879 data
->m_stmt
->fetch
.clsname
= old_clsname
;
2880 data
->m_stmt
->fetch
.ctor_args
= old_ctor_args
;
2887 static Variant
HHVM_METHOD(PDOStatement
, fetchcolumn
,
2888 int64_t column_numner
/* = 0 */) {
2889 auto data
= Native::data
<PDOStatementData
>(this_
);
2890 if (data
->m_stmt
== nullptr) {
2894 setPDOErrorNone(data
->m_stmt
->error_code
);
2895 if (!do_fetch_common(data
->m_stmt
, PDO_FETCH_ORI_NEXT
, 0, true)) {
2896 PDO_HANDLE_STMT_ERR(data
->m_stmt
);
2900 fetch_value(data
->m_stmt
, ret
, column_numner
, nullptr);
2904 static Variant
HHVM_METHOD(PDOStatement
, fetchall
, int64_t how
/* = 0 */,
2905 const Variant
& class_name
/* = null */,
2906 const Variant
& ctor_args
/* = null */) {
2907 auto self
= Native::data
<PDOStatementData
>(this_
);
2908 if (self
->m_stmt
== nullptr) {
2912 if (!pdo_stmt_verify_mode(self
->m_stmt
, how
, true)) {
2916 String old_clsname
= self
->m_stmt
->fetch
.clsname
;
2917 Variant old_ctor_args
= self
->m_stmt
->fetch
.ctor_args
;
2920 switch (how
& ~PDO_FETCH_FLAGS
) {
2921 case PDO_FETCH_CLASS
:
2922 self
->m_stmt
->fetch
.clsname
= class_name
;
2923 if (class_name
.isNull()) {
2924 self
->m_stmt
->fetch
.clsname
= "stdclass";
2926 if (!HHVM_FN(class_exists
)(self
->m_stmt
->fetch
.clsname
)) {
2927 pdo_raise_impl_error(self
->m_stmt
->dbh
, self
->m_stmt
, "HY000",
2928 "Could not find user-supplied class");
2931 if (!ctor_args
.isNull() && !ctor_args
.isArray()) {
2932 pdo_raise_impl_error(self
->m_stmt
->dbh
, self
->m_stmt
, "HY000",
2933 "ctor_args must be either NULL or an array");
2937 self
->m_stmt
->fetch
.ctor_args
= ctor_args
;
2940 do_fetch_class_prepare(self
->m_stmt
);
2944 case PDO_FETCH_FUNC
:
2945 if (!HHVM_FN(function_exists
)(class_name
.toString())) {
2946 pdo_raise_impl_error(self
->m_stmt
->dbh
, self
->m_stmt
, "HY000",
2947 "no fetch function specified");
2950 self
->m_stmt
->fetch
.func
= class_name
;
2951 do_fetch_func_prepare(self
->m_stmt
);
2955 case PDO_FETCH_COLUMN
:
2956 if (class_name
.isNull()) {
2957 self
->m_stmt
->fetch
.column
= how
& PDO_FETCH_GROUP
? -1 : 0;
2959 self
->m_stmt
->fetch
.column
= class_name
.toInt64();
2961 if (!ctor_args
.isNull()) {
2962 pdo_raise_impl_error(self
->m_stmt
->dbh
, self
->m_stmt
, "HY000",
2963 "Third parameter not allowed for "
2964 "PDO::FETCH_COLUMN");
2970 int flags
= how
& PDO_FETCH_FLAGS
;
2972 if ((how
& ~PDO_FETCH_FLAGS
) == PDO_FETCH_USE_DEFAULT
) {
2973 flags
|= self
->m_stmt
->default_fetch_type
& PDO_FETCH_FLAGS
;
2974 how
|= self
->m_stmt
->default_fetch_type
& ~PDO_FETCH_FLAGS
;
2977 Variant
*return_all
= NULL
;
2978 Variant return_value
;
2981 setPDOErrorNone(self
->m_stmt
->error_code
);
2983 if ((how
& PDO_FETCH_GROUP
) || how
== PDO_FETCH_KEY_PAIR
||
2984 (how
== PDO_FETCH_USE_DEFAULT
&&
2985 self
->m_stmt
->default_fetch_type
== PDO_FETCH_KEY_PAIR
)) {
2986 return_value
= Array::Create();
2987 return_all
= &return_value
;
2989 if (!do_fetch(self
->m_stmt
, true, data
, (PDOFetchType
)(how
| flags
),
2990 PDO_FETCH_ORI_NEXT
, 0, return_all
)) {
2995 if ((how
& PDO_FETCH_GROUP
)) {
2998 } while (do_fetch(self
->m_stmt
, true, data
, (PDOFetchType
)(how
| flags
),
2999 PDO_FETCH_ORI_NEXT
, 0, return_all
));
3000 } else if (how
== PDO_FETCH_KEY_PAIR
||
3001 (how
== PDO_FETCH_USE_DEFAULT
&&
3002 self
->m_stmt
->default_fetch_type
== PDO_FETCH_KEY_PAIR
)) {
3003 while (do_fetch(self
->m_stmt
, true, data
, (PDOFetchType
)(how
| flags
),
3004 PDO_FETCH_ORI_NEXT
, 0, return_all
)) {
3008 return_value
= Array::Create();
3010 return_value
.toArrRef().append(data
);
3012 } while (do_fetch(self
->m_stmt
, true, data
, (PDOFetchType
)(how
| flags
),
3013 PDO_FETCH_ORI_NEXT
, 0, NULL
));
3017 self
->m_stmt
->fetch
.clsname
= old_clsname
;
3018 self
->m_stmt
->fetch
.ctor_args
= old_ctor_args
;
3021 PDO_HANDLE_STMT_ERR(self
->m_stmt
);
3026 /* on no results, return an empty array */
3027 if (!return_value
.isArray()) {
3028 return_value
= Array::Create();
3031 return return_value
;
3034 static bool HHVM_METHOD(PDOStatement
, bindvalue
, const Variant
& paramno
,
3035 const Variant
& param
,
3036 int64_t type
/* = q_PDO$$PARAM_STR */) {
3037 auto data
= Native::data
<PDOStatementData
>(this_
);
3038 if (data
->m_stmt
== nullptr) {
3042 return register_bound_param(paramno
, param
, type
, 0,
3043 uninit_null(), data
->m_stmt
, true);
3046 static bool HHVM_METHOD(PDOStatement
, bindparam
, const Variant
& paramno
,
3047 VRefParam param
, int64_t type
/* = q_PDO$$PARAM_STR */,
3048 int64_t max_value_len
/* = 0 */,
3049 const Variant
& driver_params
/*= null */) {
3050 auto data
= Native::data
<PDOStatementData
>(this_
);
3051 if (data
->m_stmt
== nullptr) {
3055 return register_bound_param(paramno
, ref(param
), type
, max_value_len
,
3056 driver_params
, data
->m_stmt
, true);
3059 static bool HHVM_METHOD(PDOStatement
, bindcolumn
, const Variant
& paramno
,
3060 VRefParam param
, int64_t type
/* = q_PDO$$PARAM_STR */,
3061 int64_t max_value_len
/* = 0 */,
3062 const Variant
& driver_params
/* = null */) {
3063 auto data
= Native::data
<PDOStatementData
>(this_
);
3064 if (data
->m_stmt
== nullptr) {
3068 return register_bound_param(paramno
, ref(param
), type
, max_value_len
,
3069 driver_params
, data
->m_stmt
, false);
3072 static int64_t HHVM_METHOD(PDOStatement
, rowcount
) {
3073 auto data
= Native::data
<PDOStatementData
>(this_
);
3074 if (data
->m_stmt
== nullptr) {
3078 return data
->m_stmt
->row_count
;
3081 static Variant
HHVM_METHOD(PDOStatement
, errorcode
) {
3082 auto data
= Native::data
<PDOStatementData
>(this_
);
3083 if (data
->m_stmt
== nullptr) {
3086 if (data
->m_stmt
->error_code
[0] == '\0') {
3089 return String(data
->m_stmt
->error_code
, CopyString
);
3092 static Array
HHVM_METHOD(PDOStatement
, errorinfo
) {
3093 auto data
= Native::data
<PDOStatementData
>(this_
);
3094 if (data
->m_stmt
== nullptr) {
3099 ret
.append(String(data
->m_stmt
->error_code
, CopyString
));
3101 if (data
->m_stmt
->dbh
->conn()->support(PDOConnection::MethodFetchErr
)) {
3102 data
->m_stmt
->dbh
->conn()->fetchErr(data
->m_stmt
.get(), ret
);
3105 int error_count
= ret
.size();
3106 int error_expected_count
= 3;
3107 if (error_expected_count
> error_count
) {
3108 int error_count_diff
= error_expected_count
- error_count
;
3109 for (int i
= 0; i
< error_count_diff
; i
++) {
3110 ret
.append(uninit_null());
3116 static Variant
HHVM_METHOD(PDOStatement
, setattribute
, int64_t attribute
,
3117 const Variant
& value
) {
3118 auto data
= Native::data
<PDOStatementData
>(this_
);
3119 if (data
->m_stmt
== nullptr) {
3123 if (!data
->m_stmt
->support(PDOStatement::MethodSetAttribute
)) {
3124 pdo_raise_impl_error(data
->m_stmt
->dbh
, data
->m_stmt
, "IM001",
3125 "This driver doesn't support setting attributes");
3129 setPDOErrorNone(data
->m_stmt
->error_code
);
3130 if (data
->m_stmt
->setAttribute(attribute
, value
)) {
3133 PDO_HANDLE_STMT_ERR(data
->m_stmt
);
3137 static Variant
HHVM_METHOD(PDOStatement
, getattribute
, int64_t attribute
) {
3138 auto data
= Native::data
<PDOStatementData
>(this_
);
3139 if (data
->m_stmt
== nullptr) {
3144 if (!data
->m_stmt
->support(PDOStatement::MethodGetAttribute
)) {
3145 if (!generic_stmt_attr_get(data
->m_stmt
, ret
, attribute
)) {
3146 pdo_raise_impl_error(data
->m_stmt
->dbh
, data
->m_stmt
, "IM001",
3147 "This driver doesn't support getting attributes");
3153 setPDOErrorNone(data
->m_stmt
->error_code
);
3154 switch (data
->m_stmt
->getAttribute(attribute
, ret
)) {
3156 PDO_HANDLE_STMT_ERR(data
->m_stmt
);
3159 if (!generic_stmt_attr_get(data
->m_stmt
, ret
, attribute
)) {
3160 /* XXX: should do something better here */
3161 pdo_raise_impl_error(data
->m_stmt
->dbh
, data
->m_stmt
, "IM001",
3162 "driver doesn't support getting that attribute");
3172 static int64_t HHVM_METHOD(PDOStatement
, columncount
) {
3173 auto data
= Native::data
<PDOStatementData
>(this_
);
3174 if (data
->m_stmt
== nullptr) {
3178 return data
->m_stmt
->column_count
;
3184 s_precision("precision"),
3185 s_pdo_type("pdo_type");
3187 static Variant
HHVM_METHOD(PDOStatement
, getcolumnmeta
, int64_t column
) {
3188 auto data
= Native::data
<PDOStatementData
>(this_
);
3189 if (data
->m_stmt
== nullptr) {
3194 pdo_raise_impl_error(data
->m_stmt
->dbh
, data
->m_stmt
, "42P10",
3195 "column number must be non-negative");
3199 if (!data
->m_stmt
->support(PDOStatement::MethodGetColumnMeta
)) {
3200 pdo_raise_impl_error(data
->m_stmt
->dbh
, data
->m_stmt
, "IM001",
3201 "driver doesn't support meta data");
3205 setPDOErrorNone(data
->m_stmt
->error_code
);
3207 if (!data
->m_stmt
->getColumnMeta(column
, ret
)) {
3208 PDO_HANDLE_STMT_ERR(data
->m_stmt
);
3212 /* add stock items */
3213 auto col
= cast
<PDOColumn
>(data
->m_stmt
->columns
[column
]);
3214 ret
.set(s_name
, col
->name
);
3215 ret
.set(s_len
, (int64_t)col
->maxlen
); /* FIXME: unsigned ? */
3216 ret
.set(s_precision
, (int64_t)col
->precision
);
3217 if (col
->param_type
!= PDO_PARAM_ZVAL
) {
3218 // if param_type is PDO_PARAM_ZVAL the driver has to provide correct data
3219 ret
.set(s_pdo_type
, (int64_t)col
->param_type
);
3224 static bool HHVM_METHOD(PDOStatement
, setfetchmode
,
3225 int64_t mode
, const Array
& _argv
/* = null_array */) {
3226 auto data
= Native::data
<PDOStatementData
>(this_
);
3227 if (data
->m_stmt
== nullptr) {
3230 int argc
= _argv
.size() + 1;
3232 return pdo_stmt_set_fetch_mode(data
->m_stmt
, argc
, mode
, _argv
);
3235 static bool HHVM_METHOD(PDOStatement
, nextrowset
) {
3236 auto data
= Native::data
<PDOStatementData
>(this_
);
3237 if (data
->m_stmt
== nullptr) {
3241 if (!data
->m_stmt
->support(PDOStatement::MethodNextRowset
)) {
3242 pdo_raise_impl_error(data
->m_stmt
->dbh
, data
->m_stmt
, "IM001",
3243 "driver does not support multiple rowsets");
3247 setPDOErrorNone(data
->m_stmt
->error_code
);
3250 if (!data
->m_stmt
->columns
.empty()) {
3251 data
->m_stmt
->columns
.clear();
3252 data
->m_stmt
->column_count
= 0;
3255 if (!data
->m_stmt
->nextRowset()) {
3256 PDO_HANDLE_STMT_ERR(data
->m_stmt
);
3260 pdo_stmt_describe_columns(data
->m_stmt
);
3264 static bool HHVM_METHOD(PDOStatement
, closecursor
) {
3265 auto data
= Native::data
<PDOStatementData
>(this_
);
3266 if (data
->m_stmt
== nullptr) {
3270 if (!data
->m_stmt
->support(PDOStatement::MethodCursorCloser
)) {
3271 /* emulate it by fetching and discarding rows */
3273 while (data
->m_stmt
->fetcher(PDO_FETCH_ORI_NEXT
, 0));
3274 // if (!data->t_nextrowset()) {
3275 if (HHVM_MN(PDOStatement
, nextrowset
)(this_
)) {
3279 data
->m_stmt
->executed
= 0;
3283 setPDOErrorNone(data
->m_stmt
->error_code
);
3284 if (!data
->m_stmt
->cursorCloser()) {
3285 PDO_HANDLE_STMT_ERR(data
->m_stmt
);
3288 data
->m_stmt
->executed
= 0;
3292 static Variant
HHVM_METHOD(PDOStatement
, debugdumpparams
) {
3293 auto data
= Native::data
<PDOStatementData
>(this_
);
3294 if (data
->m_stmt
== nullptr) {
3298 auto f
= File::Open("php://output", "w");
3299 if (!f
|| f
->isInvalid()) {
3304 params
.append(data
->m_stmt
->query_string
.size());
3305 params
.append(data
->m_stmt
->query_string
.size());
3306 params
.append(data
->m_stmt
->query_string
.data());
3307 f
->printf("SQL: [%d] %.*s\n", params
);
3309 f
->printf("Params: %d\n",
3310 make_packed_array(data
->m_stmt
->bound_params
.size()));
3311 for (ArrayIter
iter(data
->m_stmt
->bound_params
); iter
; ++iter
) {
3312 if (iter
.first().isString()) {
3313 String key
= iter
.first().toString();
3314 params
= make_packed_array(key
.size(), key
.size(), key
.data());
3315 f
->printf("Key: Name: [%d] %.*s\n", params
);
3317 f
->printf("Key: Position #%ld:\n",
3318 make_packed_array(iter
.first().toInt64()));
3321 auto param
= cast
<PDOBoundParam
>(iter
.second());
3323 params
.append(param
->paramno
);
3324 params
.append(param
->name
.size());
3325 params
.append(param
->name
.size());
3326 params
.append(param
->name
.data());
3327 params
.append(param
->is_param
);
3328 params
.append(param
->param_type
);
3329 f
->printf("paramno=%d\nname=[%d] \"%.*s\"\nis_param=%d\nparam_type=%d\n",
3335 static Variant
HHVM_METHOD(PDOStatement
, current
) {
3336 auto data
= Native::data
<PDOStatementData
>(this_
);
3341 static Variant
HHVM_METHOD(PDOStatement
, key
) {
3342 auto data
= Native::data
<PDOStatementData
>(this_
);
3344 return data
->m_rowIndex
;
3347 static Variant
HHVM_METHOD(PDOStatement
, next
) {
3348 auto data
= Native::data
<PDOStatementData
>(this_
);
3350 data
->m_row
= HHVM_MN(PDOStatement
, fetch
)(this_
, PDO_FETCH_USE_DEFAULT
);
3351 if (same(data
->m_row
, false)) {
3352 data
->m_rowIndex
= -1;
3359 static Variant
HHVM_METHOD(PDOStatement
, rewind
) {
3360 auto data
= Native::data
<PDOStatementData
>(this_
);
3362 data
->m_rowIndex
= -1;
3363 HHVM_MN(PDOStatement
, next
)(this_
);
3367 static Variant
HHVM_METHOD(PDOStatement
, valid
) {
3368 auto data
= Native::data
<PDOStatementData
>(this_
);
3370 return data
->m_rowIndex
>= 0;
3373 static Variant
HHVM_METHOD(PDOStatement
, __wakeup
) {
3374 throw_pdo_exception(uninit_null(), uninit_null(),
3375 "You cannot serialize or unserialize "
3376 "PDOStatement instances");
3380 static Variant
HHVM_METHOD(PDOStatement
, __sleep
) {
3381 throw_pdo_exception(uninit_null(), uninit_null(),
3382 "You cannot serialize or unserialize "
3383 "PDOStatement instances");
3387 ///////////////////////////////////////////////////////////////////////////////
3390 static struct PDOExtension final
: Extension
{
3391 PDOExtension() : Extension("pdo", " 1.0.4dev") {}
3393 #ifdef ENABLE_EXTENSION_PDO_MYSQL
3394 std::string mysql_default_socket
;
3396 void moduleLoad(const IniSetting::Map
& ini
, Hdf config
) override
{
3397 IniSetting::Bind(this, IniSetting::PHP_INI_SYSTEM
,
3398 "pdo_mysql.default_socket", nullptr,
3399 &mysql_default_socket
);
3403 void moduleInit() override
{
3404 HHVM_FE(pdo_drivers
);
3405 HHVM_ME(PDO
, __construct
);
3406 HHVM_ME(PDO
, prepare
);
3407 HHVM_ME(PDO
, begintransaction
);
3408 HHVM_ME(PDO
, commit
);
3409 HHVM_ME(PDO
, intransaction
);
3410 HHVM_ME(PDO
, rollback
);
3411 HHVM_ME(PDO
, setattribute
);
3412 HHVM_ME(PDO
, getattribute
);
3414 HHVM_ME(PDO
, lastinsertid
);
3415 HHVM_ME(PDO
, errorcode
);
3416 HHVM_ME(PDO
, errorinfo
);
3417 HHVM_ME(PDO
, query
);
3418 HHVM_ME(PDO
, quote
);
3419 HHVM_ME(PDO
, sqlitecreatefunction
);
3420 HHVM_ME(PDO
, sqlitecreateaggregate
);
3421 HHVM_ME(PDO
, __wakeup
);
3422 HHVM_ME(PDO
, __sleep
);
3423 HHVM_STATIC_ME(PDO
, getAvailableDrivers
);
3424 HHVM_ME(PDOStatement
, execute
);
3425 HHVM_ME(PDOStatement
, fetch
);
3426 HHVM_ME(PDOStatement
, fetchobject
);
3427 HHVM_ME(PDOStatement
, fetchcolumn
);
3428 HHVM_ME(PDOStatement
, fetchall
);
3429 HHVM_ME(PDOStatement
, bindvalue
);
3430 HHVM_ME(PDOStatement
, bindparam
);
3431 HHVM_ME(PDOStatement
, bindcolumn
);
3432 HHVM_ME(PDOStatement
, rowcount
);
3433 HHVM_ME(PDOStatement
, errorcode
);
3434 HHVM_ME(PDOStatement
, errorinfo
);
3435 HHVM_ME(PDOStatement
, setattribute
);
3436 HHVM_ME(PDOStatement
, getattribute
);
3437 HHVM_ME(PDOStatement
, columncount
);
3438 HHVM_ME(PDOStatement
, getcolumnmeta
);
3439 HHVM_ME(PDOStatement
, setfetchmode
);
3440 HHVM_ME(PDOStatement
, nextrowset
);
3441 HHVM_ME(PDOStatement
, closecursor
);
3442 HHVM_ME(PDOStatement
, debugdumpparams
);
3443 HHVM_ME(PDOStatement
, current
);
3444 HHVM_ME(PDOStatement
, key
);
3445 HHVM_ME(PDOStatement
, next
);
3446 HHVM_ME(PDOStatement
, rewind
);
3447 HHVM_ME(PDOStatement
, valid
);
3448 HHVM_ME(PDOStatement
, __wakeup
);
3449 HHVM_ME(PDOStatement
, __sleep
);
3451 Native::registerClassConstant
<KindOfInt64
>(
3456 Native::registerClassConstant
<KindOfInt64
>(
3461 Native::registerClassConstant
<KindOfInt64
>(
3466 Native::registerClassConstant
<KindOfInt64
>(
3471 Native::registerClassConstant
<KindOfInt64
>(
3476 Native::registerClassConstant
<KindOfInt64
>(
3481 Native::registerClassConstant
<KindOfInt64
>(
3483 s_PARAM_INPUT_OUTPUT
.get(),
3484 q_PDO$$PARAM_INPUT_OUTPUT
3486 Native::registerClassConstant
<KindOfInt64
>(
3488 s_PARAM_EVT_ALLOC
.get(),
3489 q_PDO$$PARAM_EVT_ALLOC
3491 Native::registerClassConstant
<KindOfInt64
>(
3493 s_PARAM_EVT_FREE
.get(),
3494 q_PDO$$PARAM_EVT_FREE
3496 Native::registerClassConstant
<KindOfInt64
>(
3498 s_PARAM_EVT_EXEC_PRE
.get(),
3499 q_PDO$$PARAM_EVT_EXEC_PRE
3501 Native::registerClassConstant
<KindOfInt64
>(
3503 s_PARAM_EVT_EXEC_POST
.get(),
3504 q_PDO$$PARAM_EVT_EXEC_POST
3506 Native::registerClassConstant
<KindOfInt64
>(
3508 s_PARAM_EVT_FETCH_PRE
.get(),
3509 q_PDO$$PARAM_EVT_FETCH_PRE
3511 Native::registerClassConstant
<KindOfInt64
>(
3513 s_PARAM_EVT_FETCH_POST
.get(),
3514 q_PDO$$PARAM_EVT_FETCH_POST
3516 Native::registerClassConstant
<KindOfInt64
>(
3518 s_PARAM_EVT_NORMALIZE
.get(),
3519 q_PDO$$PARAM_EVT_NORMALIZE
3521 Native::registerClassConstant
<KindOfInt64
>(
3523 s_FETCH_USE_DEFAULT
.get(),
3524 q_PDO$$FETCH_USE_DEFAULT
3526 Native::registerClassConstant
<KindOfInt64
>(
3531 Native::registerClassConstant
<KindOfInt64
>(
3533 s_FETCH_ASSOC
.get(),
3536 Native::registerClassConstant
<KindOfInt64
>(
3541 Native::registerClassConstant
<KindOfInt64
>(
3546 Native::registerClassConstant
<KindOfInt64
>(
3551 Native::registerClassConstant
<KindOfInt64
>(
3553 s_FETCH_BOUND
.get(),
3556 Native::registerClassConstant
<KindOfInt64
>(
3558 s_FETCH_COLUMN
.get(),
3561 Native::registerClassConstant
<KindOfInt64
>(
3563 s_FETCH_CLASS
.get(),
3566 Native::registerClassConstant
<KindOfInt64
>(
3571 Native::registerClassConstant
<KindOfInt64
>(
3576 Native::registerClassConstant
<KindOfInt64
>(
3578 s_FETCH_GROUP
.get(),
3581 Native::registerClassConstant
<KindOfInt64
>(
3583 s_FETCH_UNIQUE
.get(),
3586 Native::registerClassConstant
<KindOfInt64
>(
3588 s_FETCH_KEY_PAIR
.get(),
3589 q_PDO$$FETCH_KEY_PAIR
3591 Native::registerClassConstant
<KindOfInt64
>(
3593 s_FETCH_CLASSTYPE
.get(),
3594 q_PDO$$FETCH_CLASSTYPE
3596 Native::registerClassConstant
<KindOfInt64
>(
3598 s_FETCH_SERIALIZE
.get(),
3599 q_PDO$$FETCH_SERIALIZE
3601 Native::registerClassConstant
<KindOfInt64
>(
3603 s_FETCH_PROPS_LATE
.get(),
3604 q_PDO$$FETCH_PROPS_LATE
3606 Native::registerClassConstant
<KindOfInt64
>(
3608 s_FETCH_NAMED
.get(),
3611 Native::registerClassConstant
<KindOfInt64
>(
3613 s_ATTR_AUTOCOMMIT
.get(),
3614 q_PDO$$ATTR_AUTOCOMMIT
3616 Native::registerClassConstant
<KindOfInt64
>(
3618 s_ATTR_PREFETCH
.get(),
3619 q_PDO$$ATTR_PREFETCH
3621 Native::registerClassConstant
<KindOfInt64
>(
3623 s_ATTR_TIMEOUT
.get(),
3626 Native::registerClassConstant
<KindOfInt64
>(
3628 s_ATTR_ERRMODE
.get(),
3631 Native::registerClassConstant
<KindOfInt64
>(
3633 s_ATTR_SERVER_VERSION
.get(),
3634 q_PDO$$ATTR_SERVER_VERSION
3636 Native::registerClassConstant
<KindOfInt64
>(
3638 s_ATTR_CLIENT_VERSION
.get(),
3639 q_PDO$$ATTR_CLIENT_VERSION
3641 Native::registerClassConstant
<KindOfInt64
>(
3643 s_ATTR_SERVER_INFO
.get(),
3644 q_PDO$$ATTR_SERVER_INFO
3646 Native::registerClassConstant
<KindOfInt64
>(
3648 s_ATTR_CONNECTION_STATUS
.get(),
3649 q_PDO$$ATTR_CONNECTION_STATUS
3651 Native::registerClassConstant
<KindOfInt64
>(
3656 Native::registerClassConstant
<KindOfInt64
>(
3658 s_ATTR_CURSOR_NAME
.get(),
3659 q_PDO$$ATTR_CURSOR_NAME
3661 Native::registerClassConstant
<KindOfInt64
>(
3663 s_ATTR_CURSOR
.get(),
3666 Native::registerClassConstant
<KindOfInt64
>(
3668 s_ATTR_ORACLE_NULLS
.get(),
3669 q_PDO$$ATTR_ORACLE_NULLS
3671 Native::registerClassConstant
<KindOfInt64
>(
3673 s_ATTR_PERSISTENT
.get(),
3674 q_PDO$$ATTR_PERSISTENT
3676 Native::registerClassConstant
<KindOfInt64
>(
3678 s_ATTR_STATEMENT_CLASS
.get(),
3679 q_PDO$$ATTR_STATEMENT_CLASS
3681 Native::registerClassConstant
<KindOfInt64
>(
3683 s_ATTR_FETCH_TABLE_NAMES
.get(),
3684 q_PDO$$ATTR_FETCH_TABLE_NAMES
3686 Native::registerClassConstant
<KindOfInt64
>(
3688 s_ATTR_FETCH_CATALOG_NAMES
.get(),
3689 q_PDO$$ATTR_FETCH_CATALOG_NAMES
3691 Native::registerClassConstant
<KindOfInt64
>(
3693 s_ATTR_DRIVER_NAME
.get(),
3694 q_PDO$$ATTR_DRIVER_NAME
3696 Native::registerClassConstant
<KindOfInt64
>(
3698 s_ATTR_STRINGIFY_FETCHES
.get(),
3699 q_PDO$$ATTR_STRINGIFY_FETCHES
3701 Native::registerClassConstant
<KindOfInt64
>(
3703 s_ATTR_MAX_COLUMN_LEN
.get(),
3704 q_PDO$$ATTR_MAX_COLUMN_LEN
3706 Native::registerClassConstant
<KindOfInt64
>(
3708 s_ATTR_EMULATE_PREPARES
.get(),
3709 q_PDO$$ATTR_EMULATE_PREPARES
3711 Native::registerClassConstant
<KindOfInt64
>(
3713 s_ATTR_DEFAULT_FETCH_MODE
.get(),
3714 q_PDO$$ATTR_DEFAULT_FETCH_MODE
3716 Native::registerClassConstant
<KindOfInt64
>(
3718 s_ERRMODE_SILENT
.get(),
3719 q_PDO$$ERRMODE_SILENT
3721 Native::registerClassConstant
<KindOfInt64
>(
3723 s_ERRMODE_WARNING
.get(),
3724 q_PDO$$ERRMODE_WARNING
3726 Native::registerClassConstant
<KindOfInt64
>(
3728 s_ERRMODE_EXCEPTION
.get(),
3729 q_PDO$$ERRMODE_EXCEPTION
3731 Native::registerClassConstant
<KindOfInt64
>(
3733 s_CASE_NATURAL
.get(),
3736 Native::registerClassConstant
<KindOfInt64
>(
3741 Native::registerClassConstant
<KindOfInt64
>(
3746 Native::registerClassConstant
<KindOfInt64
>(
3748 s_NULL_NATURAL
.get(),
3751 Native::registerClassConstant
<KindOfInt64
>(
3753 s_NULL_EMPTY_STRING
.get(),
3754 q_PDO$$NULL_EMPTY_STRING
3756 Native::registerClassConstant
<KindOfInt64
>(
3758 s_NULL_TO_STRING
.get(),
3759 q_PDO$$NULL_TO_STRING
3761 Native::registerClassConstant
<KindOfInt64
>(
3763 s_FETCH_ORI_NEXT
.get(),
3764 q_PDO$$FETCH_ORI_NEXT
3766 Native::registerClassConstant
<KindOfInt64
>(
3768 s_FETCH_ORI_PRIOR
.get(),
3769 q_PDO$$FETCH_ORI_PRIOR
3771 Native::registerClassConstant
<KindOfInt64
>(
3773 s_FETCH_ORI_FIRST
.get(),
3774 q_PDO$$FETCH_ORI_FIRST
3776 Native::registerClassConstant
<KindOfInt64
>(
3778 s_FETCH_ORI_LAST
.get(),
3779 q_PDO$$FETCH_ORI_LAST
3781 Native::registerClassConstant
<KindOfInt64
>(
3783 s_FETCH_ORI_ABS
.get(),
3784 q_PDO$$FETCH_ORI_ABS
3786 Native::registerClassConstant
<KindOfInt64
>(
3788 s_FETCH_ORI_REL
.get(),
3789 q_PDO$$FETCH_ORI_REL
3791 Native::registerClassConstant
<KindOfInt64
>(
3793 s_CURSOR_FWDONLY
.get(),
3794 q_PDO$$CURSOR_FWDONLY
3796 Native::registerClassConstant
<KindOfInt64
>(
3798 s_CURSOR_SCROLL
.get(),
3799 q_PDO$$CURSOR_SCROLL
3801 #ifdef ENABLE_EXTENSION_PDO_MYSQL
3802 Native::registerClassConstant
<KindOfInt64
>(
3804 s_MYSQL_ATTR_USE_BUFFERED_QUERY
.get(),
3805 q_PDO$$MYSQL_ATTR_USE_BUFFERED_QUERY
3807 Native::registerClassConstant
<KindOfInt64
>(
3809 s_MYSQL_ATTR_LOCAL_INFILE
.get(),
3810 q_PDO$$MYSQL_ATTR_LOCAL_INFILE
3812 Native::registerClassConstant
<KindOfInt64
>(
3814 s_MYSQL_ATTR_MAX_BUFFER_SIZE
.get(),
3815 q_PDO$$MYSQL_ATTR_MAX_BUFFER_SIZE
3817 Native::registerClassConstant
<KindOfInt64
>(
3819 s_MYSQL_ATTR_INIT_COMMAND
.get(),
3820 q_PDO$$MYSQL_ATTR_INIT_COMMAND
3822 Native::registerClassConstant
<KindOfInt64
>(
3824 s_MYSQL_ATTR_READ_DEFAULT_FILE
.get(),
3825 q_PDO$$MYSQL_ATTR_READ_DEFAULT_FILE
3827 Native::registerClassConstant
<KindOfInt64
>(
3829 s_MYSQL_ATTR_READ_DEFAULT_GROUP
.get(),
3830 q_PDO$$MYSQL_ATTR_READ_DEFAULT_GROUP
3832 Native::registerClassConstant
<KindOfInt64
>(
3834 s_MYSQL_ATTR_COMPRESS
.get(),
3835 q_PDO$$MYSQL_ATTR_COMPRESS
3837 Native::registerClassConstant
<KindOfInt64
>(
3839 s_MYSQL_ATTR_DIRECT_QUERY
.get(),
3840 q_PDO$$MYSQL_ATTR_DIRECT_QUERY
3842 Native::registerClassConstant
<KindOfInt64
>(
3844 s_MYSQL_ATTR_FOUND_ROWS
.get(),
3845 q_PDO$$MYSQL_ATTR_FOUND_ROWS
3847 Native::registerClassConstant
<KindOfInt64
>(
3849 s_MYSQL_ATTR_IGNORE_SPACE
.get(),
3850 q_PDO$$MYSQL_ATTR_IGNORE_SPACE
3853 Native::registerClassConstant
<KindOfPersistentString
>(
3856 q_PDO$$ERR_NONE
.get()
3859 Native::registerNativeDataInfo
<PDOData
>(
3860 s_PDO
.get(), Native::NDIFlags::NO_SWEEP
);
3861 Native::registerNativeDataInfo
<PDOStatementData
>(
3862 s_PDOStatement
.get(), Native::NDIFlags::NO_SWEEP
);
3864 loadSystemlib("pdo");
3868 //////////////////////////////////////////////////////////////////////////////