Clean up VectorEffects::init
[hiphop-php.git] / hphp / runtime / ext / pdo_sqlite.cpp
blobf47c4a2c4f1bdc23c78ede5a9a54b9368666cd4e
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
20 #include <sqlite3.h>
22 namespace HPHP {
23 IMPLEMENT_DEFAULT_EXTENSION(pdo_sqlite);
24 ///////////////////////////////////////////////////////////////////////////////
26 struct PDOSqliteError {
27 const char *file;
28 int line;
29 unsigned int errcode;
30 char *errmsg;
33 class PDOSqliteConnection : public PDOConnection {
34 public:
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 &quoted, PDOParamType paramtype);
46 virtual bool begin();
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();
55 private:
56 sqlite3 *m_db;
57 PDOSqliteError m_einfo;
60 class PDOSqliteStatement : public PDOStatement {
61 public:
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();
74 private:
75 sqlite3 *m_db;
76 sqlite3_stmt *m_stmt;
77 unsigned m_pre_fetched:1;
78 unsigned m_done: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) {
88 case SQLITE_COPY: {
89 String filename = File::TranslatePath(arg4);
90 return filename.empty() ? SQLITE_DENY : SQLITE_OK;
92 case SQLITE_ATTACH: {
93 String filename = File::TranslatePath(arg3);
94 return filename.empty() ? SQLITE_DENY : SQLITE_OK;
96 default:
97 return SQLITE_OK; /* access allowed */
101 ///////////////////////////////////////////////////////////////////////////////
103 PDOSqliteConnection::PDOSqliteConnection() : m_db(NULL) {
104 m_einfo.file = NULL;
105 m_einfo.line = 0;
106 m_einfo.errcode = 0;
107 m_einfo.errmsg = NULL;
109 alloc_own_columns = 1;
110 max_escaped_char_length = 2;
113 PDOSqliteConnection::~PDOSqliteConnection() {
114 if (m_db) {
115 sqlite3_close(m_db);
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());
129 return false;
132 if (sqlite3_open(filename.data(), &m_db) != SQLITE_OK) {
133 handleError(__FILE__, __LINE__);
134 return false;
137 sqlite3_set_authorizer(m_db, authorizer, NULL);
139 long timeout = 60;
140 if (options.exists(PDO_ATTR_TIMEOUT)) {
141 timeout = options[PDO_ATTR_TIMEOUT].toInt64();
143 sqlite3_busy_timeout(m_db, timeout * 1000);
145 return true;
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);
157 m_einfo.file = file;
158 m_einfo.line = line;
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);
167 return false;
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;
176 case SQLITE_ERROR:
177 default:
178 strcpy(*pdo_err, "HY000");
179 break;
182 return m_einfo.errcode;
185 bool PDOSqliteConnection::closer() {
186 if (m_db) {
187 sqlite3_close(m_db);
188 m_db = NULL;
190 if (m_einfo.errmsg) {
191 free(m_einfo.errmsg);
192 m_einfo.errmsg = NULL;
194 return true;
197 bool PDOSqliteConnection::preparer(CStrRef sql, sp_PDOStatement *stmt,
198 CVarRef options) {
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__);
203 return false;
206 const char *tail;
207 sqlite3_stmt *rawstmt = NULL;
208 if (sqlite3_prepare(m_db, sql.data(), sql.size(), &rawstmt, &tail)
209 == SQLITE_OK) {
211 PDOSqliteStatement *s = new PDOSqliteStatement(m_db, rawstmt);
212 *stmt = s;
213 return true;
216 handleError(__FILE__, __LINE__);
217 return false;
220 int64_t PDOSqliteConnection::doer(CStrRef sql) {
221 char *errmsg = NULL;
222 if (sqlite3_exec(m_db, sql.data(), NULL, NULL, &errmsg) != SQLITE_OK) {
223 handleError(__FILE__, __LINE__);
224 if (errmsg) sqlite3_free(errmsg);
225 return -1;
227 return sqlite3_changes(m_db);
230 bool PDOSqliteConnection::quoter(CStrRef input, String &quoted,
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));
237 return true;
240 bool PDOSqliteConnection::begin() {
241 char *errmsg = NULL;
242 if (sqlite3_exec(m_db, "BEGIN", NULL, NULL, &errmsg) != SQLITE_OK) {
243 handleError(__FILE__, __LINE__);
244 if (errmsg) sqlite3_free(errmsg);
245 return false;
247 return true;
250 bool PDOSqliteConnection::commit() {
251 char *errmsg = NULL;
252 if (sqlite3_exec(m_db, "COMMIT", NULL, NULL, &errmsg) != SQLITE_OK) {
253 handleError(__FILE__, __LINE__);
254 if (errmsg) sqlite3_free(errmsg);
255 return false;
257 return true;
260 bool PDOSqliteConnection::rollback() {
261 char *errmsg = NULL;
262 if (sqlite3_exec(m_db, "ROLLBACK", NULL, NULL, &errmsg) != SQLITE_OK) {
263 handleError(__FILE__, __LINE__);
264 if (errmsg) sqlite3_free(errmsg);
265 return false;
267 return true;
270 bool PDOSqliteConnection::setAttribute(int64_t attr, CVarRef value) {
271 switch (attr) {
272 case PDO_ATTR_TIMEOUT:
273 sqlite3_busy_timeout(m_db, value.toInt64() * 1000);
274 return true;
276 return false;
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));
288 return true;
291 int PDOSqliteConnection::getAttribute(int64_t attr, Variant &value) {
292 switch (attr) {
293 case PDO_ATTR_CLIENT_VERSION:
294 case PDO_ATTR_SERVER_VERSION:
295 value = String((char *)sqlite3_libversion(), CopyString);
296 return true;
297 default:
298 return false;
300 return true;
303 void PDOSqliteConnection::persistentShutdown() {
304 // do nothing
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() {
315 if (m_stmt) {
316 sqlite3_finalize(m_stmt);
320 bool PDOSqliteStatement::support(SupportedMethod method) {
321 switch (method) {
322 case MethodSetAttribute:
323 case MethodGetAttribute:
324 case MethodNextRowset:
325 return false;
326 default:
327 break;
329 return true;
332 int PDOSqliteStatement::handleError(const char *file, int line) {
333 PDOSqliteConnection *conn = dynamic_cast<PDOSqliteConnection*>(dbh.get());
334 assert(conn);
335 return conn->handleError(file, line, this);
338 bool PDOSqliteStatement::executer() {
339 if (executed && !m_done) {
340 sqlite3_reset(m_stmt);
343 m_done = 0;
344 switch (sqlite3_step(m_stmt)) {
345 case SQLITE_ROW:
346 m_pre_fetched = 1;
347 column_count = sqlite3_data_count(m_stmt);
348 return true;
350 case SQLITE_DONE:
351 column_count = sqlite3_column_count(m_stmt);
352 row_count = sqlite3_changes(m_db);
353 sqlite3_reset(m_stmt);
354 m_done = 1;
355 return true;
357 case SQLITE_ERROR:
358 sqlite3_reset(m_stmt);
359 case SQLITE_MISUSE:
360 case SQLITE_BUSY:
361 default:
362 handleError(__FILE__, __LINE__);
363 return false;
367 bool PDOSqliteStatement::fetcher(PDOFetchOrientation ori, long offset) {
368 if (!m_stmt) {
369 return false;
371 if (m_pre_fetched) {
372 m_pre_fetched = 0;
373 return true;
375 if (m_done) {
376 return false;
378 switch (sqlite3_step(m_stmt)) {
379 case SQLITE_ROW:
380 return true;
382 case SQLITE_DONE:
383 m_done = 1;
384 sqlite3_reset(m_stmt);
385 return false;
387 case SQLITE_ERROR:
388 sqlite3_reset(m_stmt);
389 default:
390 handleError(__FILE__, __LINE__);
391 return false;
395 bool PDOSqliteStatement::describer(int colno) {
396 if (colno < 0 || colno >= column_count) {
397 /* error invalid column */
398 handleError(__FILE__, __LINE__);
399 return false;
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;
411 col->precision = 0;
413 switch (sqlite3_column_type(m_stmt, colno)) {
414 case SQLITE_INTEGER:
415 case SQLITE_FLOAT:
416 case SQLITE3_TEXT:
417 case SQLITE_BLOB:
418 case SQLITE_NULL:
419 default:
420 col->param_type = PDO_PARAM_STR;
421 break;
424 return true;
427 bool PDOSqliteStatement::getColumn(int colno, Variant &value) {
428 if (!m_stmt) {
429 return false;
431 if (colno >= sqlite3_data_count(m_stmt)) {
432 /* error invalid column */
433 handleError(__FILE__, __LINE__);
434 return false;
436 char *ptr; int len;
437 switch (sqlite3_column_type(m_stmt, colno)) {
438 case SQLITE_NULL:
439 ptr = NULL;
440 len = 0;
441 break;
442 case SQLITE_BLOB:
443 ptr = (char*)sqlite3_column_blob(m_stmt, colno);
444 len = sqlite3_column_bytes(m_stmt, colno);
445 break;
446 case SQLITE3_TEXT:
447 ptr = (char*)sqlite3_column_text(m_stmt, colno);
448 len = sqlite3_column_bytes(m_stmt, colno);
449 break;
450 default:
451 ptr = (char*)sqlite3_column_text(m_stmt, colno);
452 len = sqlite3_column_bytes(m_stmt, colno);
453 break;
455 value = String(ptr, len, CopyString);
456 return true;
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);
465 m_done = 1;
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)) {
475 case PDO_PARAM_STMT:
476 return false;
478 case PDO_PARAM_NULL:
479 if (sqlite3_bind_null(m_stmt, param->paramno + 1) == SQLITE_OK) {
480 return true;
482 handleError(__FILE__, __LINE__);
483 return false;
485 case PDO_PARAM_INT:
486 case PDO_PARAM_BOOL:
487 if (param->parameter.isNull()) {
488 if (sqlite3_bind_null(m_stmt, param->paramno + 1) == SQLITE_OK) {
489 return true;
491 } else {
492 if (SQLITE_OK == sqlite3_bind_int(m_stmt, param->paramno + 1,
493 param->parameter.toInt64())) {
494 return true;
497 handleError(__FILE__, __LINE__);
498 return false;
500 case PDO_PARAM_LOB:
501 if (param->parameter.isResource()) {
502 Variant buf = f_stream_get_contents(param->parameter.toResource());
503 if (!same(buf, false)) {
504 param->parameter = buf;
505 } else {
506 pdo_raise_impl_error(dbh, this, "HY105",
507 "Expected a stream resource");
508 return false;
510 } else if (param->parameter.isNull()) {
511 if (sqlite3_bind_null(m_stmt, param->paramno + 1) == SQLITE_OK) {
512 return true;
514 handleError(__FILE__, __LINE__);
515 return false;
519 String sparam = param->parameter.toString();
520 if (SQLITE_OK == sqlite3_bind_blob(m_stmt, param->paramno + 1,
521 sparam.data(), sparam.size(),
522 SQLITE_STATIC)) {
523 return true;
526 handleError(__FILE__, __LINE__);
527 return false;
529 case PDO_PARAM_STR:
530 default:
531 if (param->parameter.isNull()) {
532 if (sqlite3_bind_null(m_stmt, param->paramno + 1) == SQLITE_OK) {
533 return true;
535 } else {
536 String sparam = param->parameter.toString();
537 if (SQLITE_OK == sqlite3_bind_text(m_stmt, param->paramno + 1,
538 sparam.data(), sparam.size(),
539 SQLITE_STATIC)) {
540 return true;
543 handleError(__FILE__, __LINE__);
544 return false;
547 break;
549 default:;
551 return true;
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) {
565 if (!m_stmt) {
566 return false;
568 if (colno >= sqlite3_data_count(m_stmt)) {
569 /* error invalid column */
570 handleError(__FILE__, __LINE__);
571 return false;
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);
585 if (str) {
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);
591 if (str) {
592 ret.set(s_table, String((char *)str, CopyString));
594 #endif
596 ret.set(s_flags, flags);
597 return true;
600 bool PDOSqliteStatement::cursorCloser() {
601 sqlite3_reset(m_stmt);
602 return true;
605 ///////////////////////////////////////////////////////////////////////////////
607 PDOSqlite::PDOSqlite() : PDODriver("sqlite") {
610 PDOConnection *PDOSqlite::createConnectionObject() {
611 return new PDOSqliteConnection();
614 ///////////////////////////////////////////////////////////////////////////////