2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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 +----------------------------------------------------------------------+
18 #include "hphp/runtime/ext/pdo_sqlite/pdo_sqlite.h"
19 #include "hphp/runtime/ext/sqlite3/ext_sqlite3.h"
20 #include "hphp/runtime/ext/std/ext_std_function.h"
21 #include "hphp/runtime/ext/stream/ext_stream.h"
22 #include "hphp/runtime/base/comparisons.h"
23 #include "hphp/runtime/base/file.h"
24 #include "hphp/runtime/vm/jit/translator-inline.h"
29 IMPLEMENT_DEFAULT_EXTENSION_VERSION(pdo_sqlite
, 1.0.1);
31 ///////////////////////////////////////////////////////////////////////////////
33 struct PDOSqliteStatement
: PDOStatement
{
34 DECLARE_RESOURCE_ALLOCATION(PDOSqliteStatement
);
35 PDOSqliteStatement(sqlite3
*db
, sqlite3_stmt
* stmt
);
36 virtual ~PDOSqliteStatement();
38 bool support(SupportedMethod method
) override
;
39 bool executer() override
;
40 bool fetcher(PDOFetchOrientation ori
, long offset
) override
;
41 bool describer(int colno
) override
;
42 bool getColumn(int colno
, Variant
&value
) override
;
43 bool paramHook(PDOBoundParam
* param
, PDOParamEvent event_type
) override
;
44 bool getColumnMeta(int64_t colno
, Array
&return_value
) override
;
45 bool cursorCloser() override
;
50 unsigned m_pre_fetched
:1;
53 int handleError(const char *file
, int line
);
56 ///////////////////////////////////////////////////////////////////////////////
59 authorizer(void* /*autharg*/, int access_type
, const char* arg3
,
60 const char* arg4
, const char* /*arg5*/, const char* /*arg6*/) {
61 switch (access_type
) {
63 String filename
= File::TranslatePath(arg4
);
64 return filename
.empty() ? SQLITE_DENY
: SQLITE_OK
;
67 String filename
= File::TranslatePath(arg3
);
68 return filename
.empty() ? SQLITE_DENY
: SQLITE_OK
;
71 return SQLITE_OK
; /* access allowed */
75 ///////////////////////////////////////////////////////////////////////////////
77 PDOSqliteConnection::PDOSqliteConnection() : m_db(NULL
) {
81 m_einfo
.errmsg
= NULL
;
83 alloc_own_columns
= 1;
84 max_escaped_char_length
= 2;
87 PDOSqliteConnection::~PDOSqliteConnection() {
96 bool PDOSqliteConnection::create(const Array
& options
) {
97 String filename
= data_source
.substr(0,1) == ":" ? String(data_source
) :
98 File::TranslatePath(data_source
);
99 if (filename
.empty()) {
100 throw_pdo_exception(0, Array(),
101 "safe_mode/open_basedir prohibits opening %s",
102 data_source
.c_str());
106 if (sqlite3_open(filename
.data(), &m_db
) != SQLITE_OK
) {
107 handleError(__FILE__
, __LINE__
);
111 sqlite3_set_authorizer(m_db
, authorizer
, NULL
);
114 if (options
.exists(PDO_ATTR_TIMEOUT
)) {
115 timeout
= options
[PDO_ATTR_TIMEOUT
].toInt64();
117 sqlite3_busy_timeout(m_db
, timeout
* 1000);
122 bool PDOSqliteConnection::support(SupportedMethod method
) {
123 return method
!= MethodCheckLiveness
;
126 int PDOSqliteConnection::handleError(const char *file
, int line
,
127 PDOStatement
*stmt
/* = NULL */) {
128 PDOErrorType
*pdo_err
= stmt
? &stmt
->error_code
: &error_code
;
130 m_einfo
.errcode
= sqlite3_errcode(m_db
);
134 if (m_einfo
.errcode
!= SQLITE_OK
) {
135 if (m_einfo
.errmsg
) {
136 free(m_einfo
.errmsg
);
138 m_einfo
.errmsg
= strdup((char*)sqlite3_errmsg(m_db
));
139 } else { /* no error */
140 setPDOErrorNone(*pdo_err
);
144 switch (m_einfo
.errcode
) {
145 case SQLITE_NOTFOUND
: setPDOError(*pdo_err
, "42S02"); break;
146 case SQLITE_INTERRUPT
: setPDOError(*pdo_err
, "01002"); break;
147 case SQLITE_NOLFS
: setPDOError(*pdo_err
, "HYC00"); break;
148 case SQLITE_TOOBIG
: setPDOError(*pdo_err
, "22001"); break;
149 case SQLITE_CONSTRAINT
: setPDOError(*pdo_err
, "23000"); break;
152 setPDOError(*pdo_err
, "HY000");
156 return m_einfo
.errcode
;
159 bool PDOSqliteConnection::closer() {
164 if (m_einfo
.errmsg
) {
165 free(m_einfo
.errmsg
);
166 m_einfo
.errmsg
= NULL
;
171 bool PDOSqliteConnection::preparer(const String
& sql
, sp_PDOStatement
*stmt
,
172 const Variant
& options
) {
173 if (options
.toArray().exists(PDO_ATTR_CURSOR
) &&
174 options
.toArray()[PDO_ATTR_CURSOR
].toInt64() != PDO_CURSOR_FWDONLY
) {
175 m_einfo
.errcode
= SQLITE_ERROR
;
176 handleError(__FILE__
, __LINE__
);
181 sqlite3_stmt
*rawstmt
= NULL
;
182 if (sqlite3_prepare(m_db
, sql
.data(), sql
.size(), &rawstmt
, &tail
)
185 *stmt
= req::make
<PDOSqliteStatement
>(m_db
, rawstmt
);
189 handleError(__FILE__
, __LINE__
);
193 int64_t PDOSqliteConnection::doer(const String
& sql
) {
195 if (sqlite3_exec(m_db
, sql
.data(), NULL
, NULL
, &errmsg
) != SQLITE_OK
) {
196 handleError(__FILE__
, __LINE__
);
197 if (errmsg
) sqlite3_free(errmsg
);
200 return sqlite3_changes(m_db
);
203 bool PDOSqliteConnection::quoter(const String
& input
, String
& quoted
,
204 PDOParamType
/*paramtype*/) {
205 int len
= 2 * input
.size() + 3;
206 String
s(len
, ReserveString
);
207 char *buf
= s
.mutableData();
208 sqlite3_snprintf(len
, buf
, "'%q'", input
.data());
209 quoted
= s
.setSize(strlen(buf
));
213 bool PDOSqliteConnection::begin() {
215 if (sqlite3_exec(m_db
, "BEGIN", NULL
, NULL
, &errmsg
) != SQLITE_OK
) {
216 handleError(__FILE__
, __LINE__
);
217 if (errmsg
) sqlite3_free(errmsg
);
223 bool PDOSqliteConnection::commit() {
225 if (sqlite3_exec(m_db
, "COMMIT", NULL
, NULL
, &errmsg
) != SQLITE_OK
) {
226 handleError(__FILE__
, __LINE__
);
227 if (errmsg
) sqlite3_free(errmsg
);
233 bool PDOSqliteConnection::rollback() {
235 if (sqlite3_exec(m_db
, "ROLLBACK", NULL
, NULL
, &errmsg
) != SQLITE_OK
) {
236 handleError(__FILE__
, __LINE__
);
237 if (errmsg
) sqlite3_free(errmsg
);
243 bool PDOSqliteConnection::setAttribute(int64_t attr
, const Variant
& value
) {
245 case PDO_ATTR_TIMEOUT
:
246 sqlite3_busy_timeout(m_db
, value
.toInt64() * 1000);
252 String
PDOSqliteConnection::lastId(const char* /*name*/) {
253 return (int64_t)sqlite3_last_insert_rowid(m_db
);
256 bool PDOSqliteConnection::fetchErr(PDOStatement
* /*stmt*/, Array
& info
) {
257 if (m_einfo
.errcode
) {
258 info
.append((int64_t)m_einfo
.errcode
);
259 info
.append(String(m_einfo
.errmsg
, CopyString
));
264 int PDOSqliteConnection::getAttribute(int64_t attr
, Variant
&value
) {
266 case PDO_ATTR_CLIENT_VERSION
:
267 case PDO_ATTR_SERVER_VERSION
:
268 value
= String((char *)sqlite3_libversion(), CopyString
);
276 // hidden in ext/ext_sqlite.cpp
277 void php_sqlite3_callback_func(sqlite3_context
* context
, int argc
,
278 sqlite3_value
** argv
);
280 ///////////////////////////////////////////////////////////////////////////////
282 bool PDOSqliteResource::createFunction(const String
& name
,
283 const Variant
& callback
,
285 if (!is_callable(callback
)) {
286 raise_warning("function '%s' is not callable", callback
.toString().data());
290 auto udf
= req::make_unique
<UDF
>();
292 udf
->func
= callback
;
293 udf
->argc
= argcount
;
294 udf
->name
= name
.toCppString();
296 auto stat
= sqlite3_create_function(
301 static_cast<SQLite3::UserDefinedFunc
*>(udf
.get()),
302 php_sqlite3_callback_func
,
307 if (stat
!= SQLITE_OK
) {
310 m_udfs
.emplace_back(std::move(udf
));
315 void PDOSqliteResource::sweep() {
316 for (auto& udf
: m_udfs
) {
317 udf
->func
.releaseForSweep();
318 udf
->step
.releaseForSweep();
319 udf
->fini
.releaseForSweep();
322 for (auto const& udf
: m_udfs
) {
323 sqlite3_create_function(conn()->m_db
, udf
->name
.data(), 0, SQLITE_UTF8
,
324 nullptr, nullptr, nullptr, nullptr);
328 PDOResource::sweep();
331 ///////////////////////////////////////////////////////////////////////////////
333 PDOSqliteStatement::PDOSqliteStatement(sqlite3
*db
, sqlite3_stmt
* stmt
)
334 : m_db(db
), m_stmt(stmt
), m_pre_fetched(0), m_done(0) {
335 supports_placeholders
= PDO_PLACEHOLDER_POSITIONAL
| PDO_PLACEHOLDER_NAMED
;
338 PDOSqliteStatement::~PDOSqliteStatement() {
342 void PDOSqliteStatement::sweep() {
344 sqlite3_finalize(m_stmt
);
348 bool PDOSqliteStatement::support(SupportedMethod method
) {
350 case MethodSetAttribute
:
351 case MethodGetAttribute
:
352 case MethodNextRowset
:
360 int PDOSqliteStatement::handleError(const char *file
, int line
) {
361 auto rsrc
= unsafe_cast
<PDOSqliteResource
>(dbh
);
363 auto conn
= rsrc
->conn();
365 return conn
->handleError(file
, line
, this);
368 bool PDOSqliteStatement::executer() {
369 if (executed
&& !m_done
) {
370 sqlite3_reset(m_stmt
);
374 switch (sqlite3_step(m_stmt
)) {
377 column_count
= sqlite3_data_count(m_stmt
);
381 column_count
= sqlite3_column_count(m_stmt
);
382 row_count
= sqlite3_changes(m_db
);
383 sqlite3_reset(m_stmt
);
388 sqlite3_reset(m_stmt
);
392 handleError(__FILE__
, __LINE__
);
397 bool PDOSqliteStatement::fetcher(PDOFetchOrientation
/*ori*/, long /*offset*/) {
398 SYNC_VM_REGS_SCOPED();
409 switch (sqlite3_step(m_stmt
)) {
415 sqlite3_reset(m_stmt
);
419 sqlite3_reset(m_stmt
);
421 handleError(__FILE__
, __LINE__
);
426 bool PDOSqliteStatement::describer(int colno
) {
427 if (colno
< 0 || colno
>= column_count
) {
428 /* error invalid column */
429 handleError(__FILE__
, __LINE__
);
433 if (columns
.empty()) {
434 for (int i
= 0; i
< column_count
; i
++) {
435 columns
.set(i
, Variant(req::make
<PDOColumn
>()));
439 auto col
= cast
<PDOColumn
>(columns
[colno
]);
440 col
->name
= String(sqlite3_column_name(m_stmt
, colno
), CopyString
);
441 col
->maxlen
= 0xffffffff;
444 switch (sqlite3_column_type(m_stmt
, colno
)) {
451 col
->param_type
= PDO_PARAM_STR
;
458 bool PDOSqliteStatement::getColumn(int colno
, Variant
&value
) {
462 if (colno
>= sqlite3_data_count(m_stmt
)) {
463 /* error invalid column */
464 handleError(__FILE__
, __LINE__
);
468 switch (sqlite3_column_type(m_stmt
, colno
)) {
474 ptr
= (char*)sqlite3_column_blob(m_stmt
, colno
);
475 len
= sqlite3_column_bytes(m_stmt
, colno
);
478 ptr
= (char*)sqlite3_column_text(m_stmt
, colno
);
479 len
= sqlite3_column_bytes(m_stmt
, colno
);
482 ptr
= (char*)sqlite3_column_text(m_stmt
, colno
);
483 len
= sqlite3_column_bytes(m_stmt
, colno
);
486 value
= String(ptr
, len
, CopyString
);
490 bool PDOSqliteStatement::paramHook(PDOBoundParam
* param
,
491 PDOParamEvent event_type
) {
492 switch (event_type
) {
493 case PDO_PARAM_EVT_EXEC_PRE
:
494 if (executed
&& !m_done
) {
495 sqlite3_reset(m_stmt
);
499 if (param
->is_param
) {
500 if (param
->paramno
== -1) {
501 param
->paramno
= sqlite3_bind_parameter_index(m_stmt
,
502 param
->name
.c_str()) - 1;
505 switch (PDO_PARAM_TYPE(param
->param_type
)) {
510 if (sqlite3_bind_null(m_stmt
, param
->paramno
+ 1) == SQLITE_OK
) {
513 handleError(__FILE__
, __LINE__
);
518 if (param
->parameter
.isNull()) {
519 if (sqlite3_bind_null(m_stmt
, param
->paramno
+ 1) == SQLITE_OK
) {
523 if (SQLITE_OK
== sqlite3_bind_int(m_stmt
, param
->paramno
+ 1,
524 param
->parameter
.toInt64())) {
528 handleError(__FILE__
, __LINE__
);
532 if (param
->parameter
.isResource()) {
533 Variant buf
= HHVM_FN(stream_get_contents
)(
534 param
->parameter
.toResource());
535 if (!same(buf
, false)) {
536 param
->parameter
= buf
;
538 pdo_raise_impl_error(dbh
, this, "HY105",
539 "Expected a stream resource");
542 } else if (param
->parameter
.isNull()) {
543 if (sqlite3_bind_null(m_stmt
, param
->paramno
+ 1) == SQLITE_OK
) {
546 handleError(__FILE__
, __LINE__
);
551 String sparam
= param
->parameter
.toString();
552 if (SQLITE_OK
== sqlite3_bind_blob(m_stmt
, param
->paramno
+ 1,
553 sparam
.data(), sparam
.size(),
558 handleError(__FILE__
, __LINE__
);
563 if (param
->parameter
.isNull()) {
564 if (sqlite3_bind_null(m_stmt
, param
->paramno
+ 1) == SQLITE_OK
) {
568 String sparam
= param
->parameter
.toString();
569 if (SQLITE_OK
== sqlite3_bind_text(m_stmt
, param
->paramno
+ 1,
570 sparam
.data(), sparam
.size(),
575 handleError(__FILE__
, __LINE__
);
587 s_native_type("native_type"),
592 s_integer("integer"),
593 s_sqlite_decl_type("sqlite:decl_type"),
597 bool PDOSqliteStatement::getColumnMeta(int64_t colno
, Array
&ret
) {
601 if (colno
>= sqlite3_data_count(m_stmt
)) {
602 /* error invalid column */
603 handleError(__FILE__
, __LINE__
);
607 ret
= Array::Create();
608 Array flags
= Array::Create();
609 switch (sqlite3_column_type(m_stmt
, colno
)) {
610 case SQLITE_NULL
: ret
.set(s_native_type
, s_null
); break;
611 case SQLITE_FLOAT
: ret
.set(s_native_type
, s_double
); break;
612 case SQLITE_BLOB
: flags
.append(s_blob
);
613 case SQLITE_TEXT
: ret
.set(s_native_type
, s_string
); break;
614 case SQLITE_INTEGER
: ret
.set(s_native_type
, s_integer
); break;
617 const char *str
= sqlite3_column_decltype(m_stmt
, colno
);
619 ret
.set(s_sqlite_decl_type
, String((char *)str
, CopyString
));
622 #ifdef SQLITE_ENABLE_COLUMN_METADATA
623 str
= sqlite3_column_table_name(m_stmt
, colno
);
625 ret
.set(s_table
, String((char *)str
, CopyString
));
629 ret
.set(s_flags
, flags
);
633 bool PDOSqliteStatement::cursorCloser() {
634 sqlite3_reset(m_stmt
);
638 ///////////////////////////////////////////////////////////////////////////////
640 PDOSqlite::PDOSqlite() : PDODriver("sqlite") {}
642 req::ptr
<PDOResource
> PDOSqlite::createResourceImpl() {
643 return req::make
<PDOSqliteResource
>(
644 std::make_shared
<PDOSqliteConnection
>());
647 req::ptr
<PDOResource
> PDOSqlite::createResource(
648 const sp_PDOConnection
& conn
650 return req::make
<PDOSqliteResource
>(
651 std::dynamic_pointer_cast
<PDOSqliteConnection
>(conn
));
654 ///////////////////////////////////////////////////////////////////////////////