2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 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.h"
19 #include "hphp/runtime/ext/ext_stream.h"
23 IMPLEMENT_DEFAULT_EXTENSION(pdo_sqlite
);
24 ///////////////////////////////////////////////////////////////////////////////
26 struct PDOSqliteError
{
33 class PDOSqliteConnection
: public PDOConnection
{
35 PDOSqliteConnection();
36 virtual ~PDOSqliteConnection();
37 virtual bool create(CArrRef options
);
39 int handleError(const char *file
, int line
, PDOStatement
*stmt
= NULL
);
41 virtual bool support(SupportedMethod method
);
42 virtual bool closer();
43 virtual bool preparer(CStrRef sql
, sp_PDOStatement
*stmt
, CVarRef options
);
44 virtual int64_t doer(CStrRef sql
);
45 virtual bool quoter(CStrRef input
, String
"ed
, PDOParamType paramtype
);
47 virtual bool commit();
48 virtual bool rollback();
49 virtual bool setAttribute(int64_t attr
, CVarRef value
);
50 virtual String
lastId(const char *name
);
51 virtual bool fetchErr(PDOStatement
*stmt
, Array
&info
);
52 virtual int getAttribute(int64_t attr
, Variant
&value
);
53 virtual void persistentShutdown();
57 PDOSqliteError m_einfo
;
60 class PDOSqliteStatement
: public PDOStatement
{
62 PDOSqliteStatement(sqlite3
*db
, sqlite3_stmt
* stmt
);
63 virtual ~PDOSqliteStatement();
65 virtual bool support(SupportedMethod method
);
66 virtual bool executer();
67 virtual bool fetcher(PDOFetchOrientation ori
, long offset
);
68 virtual bool describer(int colno
);
69 virtual bool getColumn(int colno
, Variant
&value
);
70 virtual bool paramHook(PDOBoundParam
*param
, PDOParamEvent event_type
);
71 virtual bool getColumnMeta(int64_t colno
, Array
&return_value
);
72 virtual bool cursorCloser();
77 unsigned m_pre_fetched
:1;
80 int handleError(const char *file
, int line
);
83 ///////////////////////////////////////////////////////////////////////////////
85 static int authorizer(void *autharg
, int access_type
, const char *arg3
,
86 const char *arg4
, const char *arg5
, const char *arg6
) {
87 switch (access_type
) {
89 String filename
= File::TranslatePath(arg4
);
90 return filename
.empty() ? SQLITE_DENY
: SQLITE_OK
;
93 String filename
= File::TranslatePath(arg3
);
94 return filename
.empty() ? SQLITE_DENY
: SQLITE_OK
;
97 return SQLITE_OK
; /* access allowed */
101 ///////////////////////////////////////////////////////////////////////////////
103 PDOSqliteConnection::PDOSqliteConnection() : m_db(NULL
) {
107 m_einfo
.errmsg
= NULL
;
109 alloc_own_columns
= 1;
110 max_escaped_char_length
= 2;
113 PDOSqliteConnection::~PDOSqliteConnection() {
117 if (m_einfo
.errmsg
) {
118 free(m_einfo
.errmsg
);
122 bool PDOSqliteConnection::create(CArrRef options
) {
123 String filename
= data_source
.substr(0,1) == ":" ? String(data_source
) :
124 File::TranslatePath(data_source
);
125 if (filename
.empty()) {
126 throw_pdo_exception(0, Array(),
127 "safe_mode/open_basedir prohibits opening %s",
128 data_source
.c_str());
132 if (sqlite3_open(filename
.data(), &m_db
) != SQLITE_OK
) {
133 handleError(__FILE__
, __LINE__
);
137 sqlite3_set_authorizer(m_db
, authorizer
, NULL
);
140 if (options
.exists(PDO_ATTR_TIMEOUT
)) {
141 timeout
= options
[PDO_ATTR_TIMEOUT
].toInt64();
143 sqlite3_busy_timeout(m_db
, timeout
* 1000);
148 bool PDOSqliteConnection::support(SupportedMethod method
) {
149 return method
!= MethodCheckLiveness
;
152 int PDOSqliteConnection::handleError(const char *file
, int line
,
153 PDOStatement
*stmt
/* = NULL */) {
154 PDOErrorType
*pdo_err
= stmt
? &stmt
->error_code
: &error_code
;
156 m_einfo
.errcode
= sqlite3_errcode(m_db
);
160 if (m_einfo
.errcode
!= SQLITE_OK
) {
161 if (m_einfo
.errmsg
) {
162 free(m_einfo
.errmsg
);
164 m_einfo
.errmsg
= strdup((char*)sqlite3_errmsg(m_db
));
165 } else { /* no error */
166 strcpy(*pdo_err
, PDO_ERR_NONE
);
170 switch (m_einfo
.errcode
) {
171 case SQLITE_NOTFOUND
: strcpy(*pdo_err
, "42S02"); break;
172 case SQLITE_INTERRUPT
: strcpy(*pdo_err
, "01002"); break;
173 case SQLITE_NOLFS
: strcpy(*pdo_err
, "HYC00"); break;
174 case SQLITE_TOOBIG
: strcpy(*pdo_err
, "22001"); break;
175 case SQLITE_CONSTRAINT
: strcpy(*pdo_err
, "23000"); break;
178 strcpy(*pdo_err
, "HY000");
182 return m_einfo
.errcode
;
185 bool PDOSqliteConnection::closer() {
190 if (m_einfo
.errmsg
) {
191 free(m_einfo
.errmsg
);
192 m_einfo
.errmsg
= NULL
;
197 bool PDOSqliteConnection::preparer(CStrRef sql
, sp_PDOStatement
*stmt
,
199 if (options
.toArray().exists(PDO_ATTR_CURSOR
) &&
200 options
[PDO_ATTR_CURSOR
].toInt64() != PDO_CURSOR_FWDONLY
) {
201 m_einfo
.errcode
= SQLITE_ERROR
;
202 handleError(__FILE__
, __LINE__
);
207 sqlite3_stmt
*rawstmt
= NULL
;
208 if (sqlite3_prepare(m_db
, sql
.data(), sql
.size(), &rawstmt
, &tail
)
211 PDOSqliteStatement
*s
= new PDOSqliteStatement(m_db
, rawstmt
);
216 handleError(__FILE__
, __LINE__
);
220 int64_t PDOSqliteConnection::doer(CStrRef sql
) {
222 if (sqlite3_exec(m_db
, sql
.data(), NULL
, NULL
, &errmsg
) != SQLITE_OK
) {
223 handleError(__FILE__
, __LINE__
);
224 if (errmsg
) sqlite3_free(errmsg
);
227 return sqlite3_changes(m_db
);
230 bool PDOSqliteConnection::quoter(CStrRef input
, String
"ed
,
231 PDOParamType paramtype
) {
232 int len
= 2 * input
.size() + 3;
233 String
s(len
, ReserveString
);
234 char *buf
= s
.mutableSlice().ptr
;
235 sqlite3_snprintf(len
, buf
, "'%q'", input
.data());
236 quoted
= s
.setSize(strlen(buf
));
240 bool PDOSqliteConnection::begin() {
242 if (sqlite3_exec(m_db
, "BEGIN", NULL
, NULL
, &errmsg
) != SQLITE_OK
) {
243 handleError(__FILE__
, __LINE__
);
244 if (errmsg
) sqlite3_free(errmsg
);
250 bool PDOSqliteConnection::commit() {
252 if (sqlite3_exec(m_db
, "COMMIT", NULL
, NULL
, &errmsg
) != SQLITE_OK
) {
253 handleError(__FILE__
, __LINE__
);
254 if (errmsg
) sqlite3_free(errmsg
);
260 bool PDOSqliteConnection::rollback() {
262 if (sqlite3_exec(m_db
, "ROLLBACK", NULL
, NULL
, &errmsg
) != SQLITE_OK
) {
263 handleError(__FILE__
, __LINE__
);
264 if (errmsg
) sqlite3_free(errmsg
);
270 bool PDOSqliteConnection::setAttribute(int64_t attr
, CVarRef value
) {
272 case PDO_ATTR_TIMEOUT
:
273 sqlite3_busy_timeout(m_db
, value
.toInt64() * 1000);
279 String
PDOSqliteConnection::lastId(const char *name
) {
280 return (int64_t)sqlite3_last_insert_rowid(m_db
);
283 bool PDOSqliteConnection::fetchErr(PDOStatement
*stmt
, Array
&info
) {
284 if (m_einfo
.errcode
) {
285 info
.append((int64_t)m_einfo
.errcode
);
286 info
.append(String(m_einfo
.errmsg
, CopyString
));
291 int PDOSqliteConnection::getAttribute(int64_t attr
, Variant
&value
) {
293 case PDO_ATTR_CLIENT_VERSION
:
294 case PDO_ATTR_SERVER_VERSION
:
295 value
= String((char *)sqlite3_libversion(), CopyString
);
303 void PDOSqliteConnection::persistentShutdown() {
307 ///////////////////////////////////////////////////////////////////////////////
309 PDOSqliteStatement::PDOSqliteStatement(sqlite3
*db
, sqlite3_stmt
* stmt
)
310 : m_db(db
), m_stmt(stmt
), m_pre_fetched(0), m_done(0) {
311 supports_placeholders
= PDO_PLACEHOLDER_POSITIONAL
| PDO_PLACEHOLDER_NAMED
;
314 PDOSqliteStatement::~PDOSqliteStatement() {
316 sqlite3_finalize(m_stmt
);
320 bool PDOSqliteStatement::support(SupportedMethod method
) {
322 case MethodSetAttribute
:
323 case MethodGetAttribute
:
324 case MethodNextRowset
:
332 int PDOSqliteStatement::handleError(const char *file
, int line
) {
333 PDOSqliteConnection
*conn
= dynamic_cast<PDOSqliteConnection
*>(dbh
.get());
335 return conn
->handleError(file
, line
, this);
338 bool PDOSqliteStatement::executer() {
339 if (executed
&& !m_done
) {
340 sqlite3_reset(m_stmt
);
344 switch (sqlite3_step(m_stmt
)) {
347 column_count
= sqlite3_data_count(m_stmt
);
351 column_count
= sqlite3_column_count(m_stmt
);
352 row_count
= sqlite3_changes(m_db
);
353 sqlite3_reset(m_stmt
);
358 sqlite3_reset(m_stmt
);
362 handleError(__FILE__
, __LINE__
);
367 bool PDOSqliteStatement::fetcher(PDOFetchOrientation ori
, long offset
) {
378 switch (sqlite3_step(m_stmt
)) {
384 sqlite3_reset(m_stmt
);
388 sqlite3_reset(m_stmt
);
390 handleError(__FILE__
, __LINE__
);
395 bool PDOSqliteStatement::describer(int colno
) {
396 if (colno
< 0 || colno
>= column_count
) {
397 /* error invalid column */
398 handleError(__FILE__
, __LINE__
);
402 if (columns
.empty()) {
403 for (int i
= 0; i
< column_count
; i
++) {
404 columns
.set(i
, Resource(new PDOColumn()));
408 PDOColumn
*col
= columns
[colno
].toResource().getTyped
<PDOColumn
>();
409 col
->name
= String(sqlite3_column_name(m_stmt
, colno
), CopyString
);
410 col
->maxlen
= 0xffffffff;
413 switch (sqlite3_column_type(m_stmt
, colno
)) {
420 col
->param_type
= PDO_PARAM_STR
;
427 bool PDOSqliteStatement::getColumn(int colno
, Variant
&value
) {
431 if (colno
>= sqlite3_data_count(m_stmt
)) {
432 /* error invalid column */
433 handleError(__FILE__
, __LINE__
);
437 switch (sqlite3_column_type(m_stmt
, colno
)) {
443 ptr
= (char*)sqlite3_column_blob(m_stmt
, colno
);
444 len
= sqlite3_column_bytes(m_stmt
, colno
);
447 ptr
= (char*)sqlite3_column_text(m_stmt
, colno
);
448 len
= sqlite3_column_bytes(m_stmt
, colno
);
451 ptr
= (char*)sqlite3_column_text(m_stmt
, colno
);
452 len
= sqlite3_column_bytes(m_stmt
, colno
);
455 value
= String(ptr
, len
, CopyString
);
459 bool PDOSqliteStatement::paramHook(PDOBoundParam
*param
,
460 PDOParamEvent event_type
) {
461 switch (event_type
) {
462 case PDO_PARAM_EVT_EXEC_PRE
:
463 if (executed
&& !m_done
) {
464 sqlite3_reset(m_stmt
);
468 if (param
->is_param
) {
469 if (param
->paramno
== -1) {
470 param
->paramno
= sqlite3_bind_parameter_index(m_stmt
,
471 param
->name
.c_str()) - 1;
474 switch (PDO_PARAM_TYPE(param
->param_type
)) {
479 if (sqlite3_bind_null(m_stmt
, param
->paramno
+ 1) == SQLITE_OK
) {
482 handleError(__FILE__
, __LINE__
);
487 if (param
->parameter
.isNull()) {
488 if (sqlite3_bind_null(m_stmt
, param
->paramno
+ 1) == SQLITE_OK
) {
492 if (SQLITE_OK
== sqlite3_bind_int(m_stmt
, param
->paramno
+ 1,
493 param
->parameter
.toInt64())) {
497 handleError(__FILE__
, __LINE__
);
501 if (param
->parameter
.isResource()) {
502 Variant buf
= f_stream_get_contents(param
->parameter
.toResource());
503 if (!same(buf
, false)) {
504 param
->parameter
= buf
;
506 pdo_raise_impl_error(dbh
, this, "HY105",
507 "Expected a stream resource");
510 } else if (param
->parameter
.isNull()) {
511 if (sqlite3_bind_null(m_stmt
, param
->paramno
+ 1) == SQLITE_OK
) {
514 handleError(__FILE__
, __LINE__
);
519 String sparam
= param
->parameter
.toString();
520 if (SQLITE_OK
== sqlite3_bind_blob(m_stmt
, param
->paramno
+ 1,
521 sparam
.data(), sparam
.size(),
526 handleError(__FILE__
, __LINE__
);
531 if (param
->parameter
.isNull()) {
532 if (sqlite3_bind_null(m_stmt
, param
->paramno
+ 1) == SQLITE_OK
) {
536 String sparam
= param
->parameter
.toString();
537 if (SQLITE_OK
== sqlite3_bind_text(m_stmt
, param
->paramno
+ 1,
538 sparam
.data(), sparam
.size(),
543 handleError(__FILE__
, __LINE__
);
554 static const StaticString
s_native_type("native_type");
555 static const StaticString
s_null("null");
556 static const StaticString
s_double("double");
557 static const StaticString
s_blob("blob");
558 static const StaticString
s_string("string");
559 static const StaticString
s_integer("integer");
560 static const StaticString
s_sqlite_decl_type("sqlite:decl_type");
561 static const StaticString
s_table("table");
562 static const StaticString
s_flags("flags");
564 bool PDOSqliteStatement::getColumnMeta(int64_t colno
, Array
&ret
) {
568 if (colno
>= sqlite3_data_count(m_stmt
)) {
569 /* error invalid column */
570 handleError(__FILE__
, __LINE__
);
574 ret
= Array::Create();
575 Array flags
= Array::Create();
576 switch (sqlite3_column_type(m_stmt
, colno
)) {
577 case SQLITE_NULL
: ret
.set(s_native_type
, s_null
); break;
578 case SQLITE_FLOAT
: ret
.set(s_native_type
, s_double
); break;
579 case SQLITE_BLOB
: flags
.append(s_blob
);
580 case SQLITE_TEXT
: ret
.set(s_native_type
, s_string
); break;
581 case SQLITE_INTEGER
: ret
.set(s_native_type
, s_integer
); break;
584 const char *str
= sqlite3_column_decltype(m_stmt
, colno
);
586 ret
.set(s_sqlite_decl_type
, String((char *)str
, CopyString
));
589 #ifdef SQLITE_ENABLE_COLUMN_METADATA
590 str
= sqlite3_column_table_name(m_stmt
, colno
);
592 ret
.set(s_table
, String((char *)str
, CopyString
));
596 ret
.set(s_flags
, flags
);
600 bool PDOSqliteStatement::cursorCloser() {
601 sqlite3_reset(m_stmt
);
605 ///////////////////////////////////////////////////////////////////////////////
607 PDOSqlite::PDOSqlite() : PDODriver("sqlite") {
610 PDOConnection
*PDOSqlite::createConnectionObject() {
611 return new PDOSqliteConnection();
614 ///////////////////////////////////////////////////////////////////////////////