comment out unused parameters
[hiphop-php.git] / hphp / runtime / ext / pdo_sqlite / pdo_sqlite.cpp
blobafd6a0b8f47e3b6de9ee00c22148b01b1f809175
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
25 #include <sqlite3.h>
27 namespace HPHP {
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;
47 private:
48 sqlite3 *m_db;
49 sqlite3_stmt *m_stmt;
50 unsigned m_pre_fetched:1;
51 unsigned m_done:1;
53 int handleError(const char *file, int line);
56 ///////////////////////////////////////////////////////////////////////////////
58 static int
59 authorizer(void* /*autharg*/, int access_type, const char* arg3,
60 const char* arg4, const char* /*arg5*/, const char* /*arg6*/) {
61 switch (access_type) {
62 case SQLITE_COPY: {
63 String filename = File::TranslatePath(arg4);
64 return filename.empty() ? SQLITE_DENY : SQLITE_OK;
66 case SQLITE_ATTACH: {
67 String filename = File::TranslatePath(arg3);
68 return filename.empty() ? SQLITE_DENY : SQLITE_OK;
70 default:
71 return SQLITE_OK; /* access allowed */
75 ///////////////////////////////////////////////////////////////////////////////
77 PDOSqliteConnection::PDOSqliteConnection() : m_db(NULL) {
78 m_einfo.file = NULL;
79 m_einfo.line = 0;
80 m_einfo.errcode = 0;
81 m_einfo.errmsg = NULL;
83 alloc_own_columns = 1;
84 max_escaped_char_length = 2;
87 PDOSqliteConnection::~PDOSqliteConnection() {
88 if (m_db) {
89 sqlite3_close(m_db);
91 if (m_einfo.errmsg) {
92 free(m_einfo.errmsg);
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());
103 return false;
106 if (sqlite3_open(filename.data(), &m_db) != SQLITE_OK) {
107 handleError(__FILE__, __LINE__);
108 return false;
111 sqlite3_set_authorizer(m_db, authorizer, NULL);
113 long timeout = 60;
114 if (options.exists(PDO_ATTR_TIMEOUT)) {
115 timeout = options[PDO_ATTR_TIMEOUT].toInt64();
117 sqlite3_busy_timeout(m_db, timeout * 1000);
119 return true;
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);
131 m_einfo.file = file;
132 m_einfo.line = line;
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);
141 return false;
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;
150 case SQLITE_ERROR:
151 default:
152 setPDOError(*pdo_err, "HY000");
153 break;
156 return m_einfo.errcode;
159 bool PDOSqliteConnection::closer() {
160 if (m_db) {
161 sqlite3_close(m_db);
162 m_db = NULL;
164 if (m_einfo.errmsg) {
165 free(m_einfo.errmsg);
166 m_einfo.errmsg = NULL;
168 return true;
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__);
177 return false;
180 const char *tail;
181 sqlite3_stmt *rawstmt = NULL;
182 if (sqlite3_prepare(m_db, sql.data(), sql.size(), &rawstmt, &tail)
183 == SQLITE_OK) {
185 *stmt = req::make<PDOSqliteStatement>(m_db, rawstmt);
186 return true;
189 handleError(__FILE__, __LINE__);
190 return false;
193 int64_t PDOSqliteConnection::doer(const String& sql) {
194 char *errmsg = NULL;
195 if (sqlite3_exec(m_db, sql.data(), NULL, NULL, &errmsg) != SQLITE_OK) {
196 handleError(__FILE__, __LINE__);
197 if (errmsg) sqlite3_free(errmsg);
198 return -1;
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));
210 return true;
213 bool PDOSqliteConnection::begin() {
214 char *errmsg = NULL;
215 if (sqlite3_exec(m_db, "BEGIN", NULL, NULL, &errmsg) != SQLITE_OK) {
216 handleError(__FILE__, __LINE__);
217 if (errmsg) sqlite3_free(errmsg);
218 return false;
220 return true;
223 bool PDOSqliteConnection::commit() {
224 char *errmsg = NULL;
225 if (sqlite3_exec(m_db, "COMMIT", NULL, NULL, &errmsg) != SQLITE_OK) {
226 handleError(__FILE__, __LINE__);
227 if (errmsg) sqlite3_free(errmsg);
228 return false;
230 return true;
233 bool PDOSqliteConnection::rollback() {
234 char *errmsg = NULL;
235 if (sqlite3_exec(m_db, "ROLLBACK", NULL, NULL, &errmsg) != SQLITE_OK) {
236 handleError(__FILE__, __LINE__);
237 if (errmsg) sqlite3_free(errmsg);
238 return false;
240 return true;
243 bool PDOSqliteConnection::setAttribute(int64_t attr, const Variant& value) {
244 switch (attr) {
245 case PDO_ATTR_TIMEOUT:
246 sqlite3_busy_timeout(m_db, value.toInt64() * 1000);
247 return true;
249 return false;
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));
261 return true;
264 int PDOSqliteConnection::getAttribute(int64_t attr, Variant &value) {
265 switch (attr) {
266 case PDO_ATTR_CLIENT_VERSION:
267 case PDO_ATTR_SERVER_VERSION:
268 value = String((char *)sqlite3_libversion(), CopyString);
269 return true;
270 default:
271 return false;
273 return true;
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,
284 int argcount) {
285 if (!is_callable(callback)) {
286 raise_warning("function '%s' is not callable", callback.toString().data());
287 return false;
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(
297 conn()->m_db,
298 udf->name.c_str(),
299 argcount,
300 SQLITE_UTF8,
301 static_cast<SQLite3::UserDefinedFunc*>(udf.get()),
302 php_sqlite3_callback_func,
303 nullptr,
304 nullptr
307 if (stat != SQLITE_OK) {
308 return false;
310 m_udfs.emplace_back(std::move(udf));
312 return true;
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);
326 m_udfs.clear();
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() {
339 sweep();
342 void PDOSqliteStatement::sweep() {
343 if (m_stmt) {
344 sqlite3_finalize(m_stmt);
348 bool PDOSqliteStatement::support(SupportedMethod method) {
349 switch (method) {
350 case MethodSetAttribute:
351 case MethodGetAttribute:
352 case MethodNextRowset:
353 return false;
354 default:
355 break;
357 return true;
360 int PDOSqliteStatement::handleError(const char *file, int line) {
361 auto rsrc = unsafe_cast<PDOSqliteResource>(dbh);
362 assert(rsrc);
363 auto conn = rsrc->conn();
364 assert(conn);
365 return conn->handleError(file, line, this);
368 bool PDOSqliteStatement::executer() {
369 if (executed && !m_done) {
370 sqlite3_reset(m_stmt);
373 m_done = 0;
374 switch (sqlite3_step(m_stmt)) {
375 case SQLITE_ROW:
376 m_pre_fetched = 1;
377 column_count = sqlite3_data_count(m_stmt);
378 return true;
380 case SQLITE_DONE:
381 column_count = sqlite3_column_count(m_stmt);
382 row_count = sqlite3_changes(m_db);
383 sqlite3_reset(m_stmt);
384 m_done = 1;
385 return true;
387 case SQLITE_ERROR:
388 sqlite3_reset(m_stmt);
389 case SQLITE_MISUSE:
390 case SQLITE_BUSY:
391 default:
392 handleError(__FILE__, __LINE__);
393 return false;
397 bool PDOSqliteStatement::fetcher(PDOFetchOrientation /*ori*/, long /*offset*/) {
398 SYNC_VM_REGS_SCOPED();
399 if (!m_stmt) {
400 return false;
402 if (m_pre_fetched) {
403 m_pre_fetched = 0;
404 return true;
406 if (m_done) {
407 return false;
409 switch (sqlite3_step(m_stmt)) {
410 case SQLITE_ROW:
411 return true;
413 case SQLITE_DONE:
414 m_done = 1;
415 sqlite3_reset(m_stmt);
416 return false;
418 case SQLITE_ERROR:
419 sqlite3_reset(m_stmt);
420 default:
421 handleError(__FILE__, __LINE__);
422 return false;
426 bool PDOSqliteStatement::describer(int colno) {
427 if (colno < 0 || colno >= column_count) {
428 /* error invalid column */
429 handleError(__FILE__, __LINE__);
430 return false;
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;
442 col->precision = 0;
444 switch (sqlite3_column_type(m_stmt, colno)) {
445 case SQLITE_INTEGER:
446 case SQLITE_FLOAT:
447 case SQLITE3_TEXT:
448 case SQLITE_BLOB:
449 case SQLITE_NULL:
450 default:
451 col->param_type = PDO_PARAM_STR;
452 break;
455 return true;
458 bool PDOSqliteStatement::getColumn(int colno, Variant &value) {
459 if (!m_stmt) {
460 return false;
462 if (colno >= sqlite3_data_count(m_stmt)) {
463 /* error invalid column */
464 handleError(__FILE__, __LINE__);
465 return false;
467 char *ptr; int len;
468 switch (sqlite3_column_type(m_stmt, colno)) {
469 case SQLITE_NULL:
470 ptr = NULL;
471 len = 0;
472 break;
473 case SQLITE_BLOB:
474 ptr = (char*)sqlite3_column_blob(m_stmt, colno);
475 len = sqlite3_column_bytes(m_stmt, colno);
476 break;
477 case SQLITE3_TEXT:
478 ptr = (char*)sqlite3_column_text(m_stmt, colno);
479 len = sqlite3_column_bytes(m_stmt, colno);
480 break;
481 default:
482 ptr = (char*)sqlite3_column_text(m_stmt, colno);
483 len = sqlite3_column_bytes(m_stmt, colno);
484 break;
486 value = String(ptr, len, CopyString);
487 return true;
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);
496 m_done = 1;
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)) {
506 case PDO_PARAM_STMT:
507 return false;
509 case PDO_PARAM_NULL:
510 if (sqlite3_bind_null(m_stmt, param->paramno + 1) == SQLITE_OK) {
511 return true;
513 handleError(__FILE__, __LINE__);
514 return false;
516 case PDO_PARAM_INT:
517 case PDO_PARAM_BOOL:
518 if (param->parameter.isNull()) {
519 if (sqlite3_bind_null(m_stmt, param->paramno + 1) == SQLITE_OK) {
520 return true;
522 } else {
523 if (SQLITE_OK == sqlite3_bind_int(m_stmt, param->paramno + 1,
524 param->parameter.toInt64())) {
525 return true;
528 handleError(__FILE__, __LINE__);
529 return false;
531 case PDO_PARAM_LOB:
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;
537 } else {
538 pdo_raise_impl_error(dbh, this, "HY105",
539 "Expected a stream resource");
540 return false;
542 } else if (param->parameter.isNull()) {
543 if (sqlite3_bind_null(m_stmt, param->paramno + 1) == SQLITE_OK) {
544 return true;
546 handleError(__FILE__, __LINE__);
547 return false;
551 String sparam = param->parameter.toString();
552 if (SQLITE_OK == sqlite3_bind_blob(m_stmt, param->paramno + 1,
553 sparam.data(), sparam.size(),
554 SQLITE_STATIC)) {
555 return true;
558 handleError(__FILE__, __LINE__);
559 return false;
561 case PDO_PARAM_STR:
562 default:
563 if (param->parameter.isNull()) {
564 if (sqlite3_bind_null(m_stmt, param->paramno + 1) == SQLITE_OK) {
565 return true;
567 } else {
568 String sparam = param->parameter.toString();
569 if (SQLITE_OK == sqlite3_bind_text(m_stmt, param->paramno + 1,
570 sparam.data(), sparam.size(),
571 SQLITE_STATIC)) {
572 return true;
575 handleError(__FILE__, __LINE__);
576 return false;
579 break;
581 default:;
583 return true;
586 const StaticString
587 s_native_type("native_type"),
588 s_null("null"),
589 s_double("double"),
590 s_blob("blob"),
591 s_string("string"),
592 s_integer("integer"),
593 s_sqlite_decl_type("sqlite:decl_type"),
594 s_table("table"),
595 s_flags("flags");
597 bool PDOSqliteStatement::getColumnMeta(int64_t colno, Array &ret) {
598 if (!m_stmt) {
599 return false;
601 if (colno >= sqlite3_data_count(m_stmt)) {
602 /* error invalid column */
603 handleError(__FILE__, __LINE__);
604 return false;
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);
618 if (str) {
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);
624 if (str) {
625 ret.set(s_table, String((char *)str, CopyString));
627 #endif
629 ret.set(s_flags, flags);
630 return true;
633 bool PDOSqliteStatement::cursorCloser() {
634 sqlite3_reset(m_stmt);
635 return true;
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 ///////////////////////////////////////////////////////////////////////////////