Codemod asserts to assertxs in the runtime
[hiphop-php.git] / hphp / runtime / ext / sqlite3 / ext_sqlite3.cpp
blobd08134fc80ba58d4c53d28066c5a9956cf4ee9a7
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/sqlite3/ext_sqlite3.h"
19 #include "hphp/runtime/ext/stream/ext_stream.h"
20 #include "hphp/runtime/ext/std/ext_std_function.h"
21 #include "hphp/runtime/base/array-init.h"
22 #include "hphp/runtime/base/builtin-functions.h"
23 #include "hphp/runtime/base/comparisons.h"
24 #include "hphp/runtime/base/exceptions.h"
25 #include "hphp/runtime/base/file.h"
26 #include "hphp/runtime/base/file-util.h"
27 #include "hphp/runtime/vm/jit/translator-inline.h"
28 #include "hphp/runtime/vm/native-data.h"
30 #include "hphp/system/systemlib.h"
32 namespace HPHP {
34 #define PHP_SQLITE3_ASSOC (1<<0)
35 #define PHP_SQLITE3_NUM (1<<1)
36 #define PHP_SQLITE3_BOTH (PHP_SQLITE3_ASSOC|PHP_SQLITE3_NUM)
38 #define IMPLEMENT_GET_CLASS(cls) \
39 Class *cls::getClass() { \
40 if (s_class == nullptr) { \
41 s_class = Unit::lookupClass(s_className.get()); \
42 assertx(s_class); \
43 } \
44 return s_class; \
45 } \
47 ///////////////////////////////////////////////////////////////////////////////
48 // helpers
50 struct php_sqlite3_agg_context {
51 Variant context;
52 int64_t row_count;
55 static Variant get_column_value(sqlite3_stmt *stmt, int column) {
56 assertx(stmt);
57 Variant data;
58 switch (sqlite3_column_type(stmt, column)) {
59 case SQLITE_INTEGER:
60 data = (int64_t)sqlite3_column_int64(stmt, column);
61 break;
62 case SQLITE_FLOAT:
63 data = (double)sqlite3_column_double(stmt, column);
64 break;
65 case SQLITE_NULL:
66 break;
67 case SQLITE3_TEXT:
68 data = String((char*)sqlite3_column_text(stmt, column), CopyString);
69 break;
70 case SQLITE_BLOB:
71 default:
72 data = String((char*)sqlite3_column_blob(stmt, column),
73 sqlite3_column_bytes(stmt, column), CopyString);
75 return data;
78 static Variant get_value(sqlite3_value *argv) {
79 Variant value;
80 switch (sqlite3_value_type(argv)) {
81 case SQLITE_INTEGER:
82 value = (int64_t)sqlite3_value_int(argv);
83 break;
84 case SQLITE_FLOAT:
85 value = (double)sqlite3_value_double(argv);
86 break;
87 case SQLITE_NULL:
88 break;
89 case SQLITE_BLOB:
90 case SQLITE3_TEXT:
91 default:
92 value = String((char*)sqlite3_value_text(argv),
93 sqlite3_value_bytes(argv), CopyString);
94 break;
96 return value;
99 static void sqlite3_do_callback(sqlite3_context *context,
100 const Variant& callback,
101 int argc,
102 sqlite3_value **argv,
103 bool is_agg) {
104 Array params = Array::Create();
105 php_sqlite3_agg_context *agg_context = nullptr;
106 if (is_agg) {
107 agg_context = (php_sqlite3_agg_context *)sqlite3_aggregate_context
108 (context, sizeof(php_sqlite3_agg_context));
109 params.appendRef(agg_context->context);
110 params.append(agg_context->row_count);
112 for (int i = 0; i < argc; i++) {
113 params.append(get_value(argv[i]));
115 Variant ret = vm_call_user_func(callback, params);
117 if (!is_agg || !argv) {
118 /* only set the sqlite return value if we are a scalar function,
119 * or if we are finalizing an aggregate */
120 if (ret.isInteger()) {
121 sqlite3_result_int(context, ret.toInt64());
122 } else if (ret.isNull()) {
123 sqlite3_result_null(context);
124 } else if (ret.isDouble()) {
125 sqlite3_result_double(context, ret.toDouble());
126 } else {
127 String sret = ret.toString();
128 sqlite3_result_text(context, sret.data(), sret.size(), SQLITE_TRANSIENT);
130 } else {
131 /* we're stepping in an aggregate; the return value goes into
132 * the context */
133 agg_context->context = ret;
137 void php_sqlite3_callback_func(sqlite3_context *context, int argc,
138 sqlite3_value **argv) {
139 SQLite3::UserDefinedFunc *udf =
140 (SQLite3::UserDefinedFunc*)sqlite3_user_data(context);
141 sqlite3_do_callback(context, udf->func, argc, argv, false);
144 static void php_sqlite3_callback_step(sqlite3_context *context, int argc,
145 sqlite3_value **argv) {
146 php_sqlite3_agg_context *agg_context =
147 (php_sqlite3_agg_context *)sqlite3_aggregate_context
148 (context, sizeof(php_sqlite3_agg_context));
149 agg_context->row_count++;
151 SQLite3::UserDefinedFunc *udf =
152 (SQLite3::UserDefinedFunc*)sqlite3_user_data(context);
153 sqlite3_do_callback(context, udf->step, argc, argv, true);
156 static void php_sqlite3_callback_final(sqlite3_context *context) {
157 php_sqlite3_agg_context *agg_context =
158 (php_sqlite3_agg_context *)sqlite3_aggregate_context
159 (context, sizeof(php_sqlite3_agg_context));
160 agg_context->row_count = 0;
162 SQLite3::UserDefinedFunc *udf =
163 (SQLite3::UserDefinedFunc*)sqlite3_user_data(context);
164 sqlite3_do_callback(context, udf->fini, 0, nullptr, true);
167 ///////////////////////////////////////////////////////////////////////////////
168 // sqlite3
170 Class *SQLite3::s_class = nullptr;
171 const StaticString SQLite3::s_className("SQLite3");
173 IMPLEMENT_GET_CLASS(SQLite3)
175 SQLite3::SQLite3() : m_raw_db(nullptr) {
178 SQLite3::~SQLite3() {
179 if (m_raw_db) {
180 sqlite3_close(m_raw_db);
184 void HHVM_METHOD(SQLite3, __construct,
185 const String& filename,
186 int64_t flags /* = SQLITE3_OPEN_READWRITE |
187 SQLITE3_OPEN_CREATE */,
188 const Variant& encryption_key /* = null */) {
189 HHVM_MN(SQLite3, open)(this_, filename, flags, encryption_key);
192 void SQLite3::validate() const {
193 if (!m_raw_db) {
194 SystemLib::throwExceptionObject("SQLite3 object was not initialized");
198 void HHVM_METHOD(SQLite3, open, const String& filename,
199 int64_t flags /* = SQLITE3_OPEN_READWRITE |
200 SQLITE3_OPEN_CREATE */,
201 const Variant& /*encryption_key*/ /* = null */) {
202 auto *data = Native::data<SQLite3>(this_);
203 if (data->m_raw_db) {
204 SystemLib::throwExceptionObject("Already initialized DB Object");
207 String fname;
208 if (strncmp(filename.data(), ":memory:", 8) != 0) {
209 FileUtil::checkPathAndError(filename, "SQLite3::__construct", 1);
210 fname = File::TranslatePath(filename);
211 } else {
212 fname = filename; // in-memory db
215 if (sqlite3_open_v2(fname.data(), &data->m_raw_db, flags, nullptr)
216 != SQLITE_OK) {
217 SystemLib::throwExceptionObject((std::string("Unable to open database: ") +
218 sqlite3_errmsg(data->m_raw_db)).c_str());
221 #ifdef SQLITE_HAS_CODEC
222 const String& str_encryption_key = encryption_key.isNull()
223 ? null_string
224 : encryption_key.toString();
225 if (!str_encryption_key.empty() &&
226 sqlite3_key(data->m_raw_db, str_encryption_key.data(),
227 str_encryption_key.size()) != SQLITE_OK) {
228 SystemLib::throwExceptionObject((std::string("Unable to open database: ") +
229 sqlite3_errmsg(data->m_raw_db)).c_str());
231 #endif
234 bool HHVM_METHOD(SQLite3, busytimeout,
235 int64_t msecs) {
236 auto *data = Native::data<SQLite3>(this_);
237 data->validate();
238 int errcode = sqlite3_busy_timeout(data->m_raw_db, msecs);
239 if (errcode != SQLITE_OK) {
240 raise_warning("Unable to set busy timeout: %d, %s", errcode,
241 sqlite3_errmsg(data->m_raw_db));
242 return false;
244 return true;
247 bool HHVM_METHOD(SQLite3, close) {
248 auto *data = Native::data<SQLite3>(this_);
249 if (data->m_raw_db) {
250 int errcode = sqlite3_close(data->m_raw_db);
251 if (errcode != SQLITE_OK) {
252 raise_warning("Unable to close database: %d, %s", errcode,
253 sqlite3_errmsg(data->m_raw_db));
254 return false;
256 data->m_raw_db = nullptr;
258 return true;
261 bool HHVM_METHOD(SQLite3, exec,
262 const String& sql) {
263 auto *data = Native::data<SQLite3>(this_);
264 SYNC_VM_REGS_SCOPED();
265 data->validate();
267 char *errtext = nullptr;
268 if (sqlite3_exec(data->m_raw_db, sql.data(), nullptr, nullptr, &errtext)
269 != SQLITE_OK) {
270 raise_warning("%s", errtext);
271 sqlite3_free(errtext);
272 return false;
274 return true;
277 const StaticString
278 s_versionString("versionString"),
279 s_versionNumber("versionNumber");
281 Array HHVM_STATIC_METHOD(SQLite3, version) {
282 return make_map_array(
283 s_versionString, String((char*)sqlite3_libversion(), CopyString),
284 s_versionNumber, (int64_t)sqlite3_libversion_number()
288 int64_t HHVM_METHOD(SQLite3, lastinsertrowid) {
289 auto *data = Native::data<SQLite3>(this_);
290 data->validate();
291 return sqlite3_last_insert_rowid(data->m_raw_db);
294 int64_t HHVM_METHOD(SQLite3, lasterrorcode) {
295 auto *data = Native::data<SQLite3>(this_);
296 data->validate();
297 return sqlite3_errcode(data->m_raw_db);
300 String HHVM_METHOD(SQLite3, lasterrormsg) {
301 auto *data = Native::data<SQLite3>(this_);
302 data->validate();
303 return String((char*)sqlite3_errmsg(data->m_raw_db), CopyString);
306 bool HHVM_METHOD(SQLite3, loadextension,
307 const String& extension) {
308 auto *data = Native::data<SQLite3>(this_);
309 data->validate();
311 if (!FileUtil::checkPathAndWarn(extension, "SQLite3::loadExtension", 1)) {
312 return false;
315 String translated = File::TranslatePath(extension);
316 if (translated.empty()) {
317 raise_warning("Unable to load extension at '%s'", extension.data());
318 return false;
321 char *errtext = nullptr;
322 sqlite3_enable_load_extension(data->m_raw_db, 1);
323 if (sqlite3_load_extension(data->m_raw_db, translated.data(), 0, &errtext)
324 != SQLITE_OK) {
325 raise_warning("%s", errtext);
326 sqlite3_free(errtext);
327 sqlite3_enable_load_extension(data->m_raw_db, 0);
328 return false;
330 sqlite3_enable_load_extension(data->m_raw_db, 0);
331 return true;
334 int64_t HHVM_METHOD(SQLite3, changes) {
335 auto *data = Native::data<SQLite3>(this_);
336 data->validate();
337 return sqlite3_changes(data->m_raw_db);
340 String HHVM_STATIC_METHOD(SQLite3, escapestring,
341 const String& sql) {
342 if (!sql.empty()) {
343 char *ret = sqlite3_mprintf("%q", sql.data());
344 if (ret) {
345 String sret(ret, CopyString);
346 sqlite3_free(ret);
347 return sret;
350 return empty_string();
353 Variant HHVM_METHOD(SQLite3, prepare,
354 const String& sql) {
355 auto *data = Native::data<SQLite3>(this_);
356 data->validate();
357 if (!sql.empty()) {
358 Object ret{SQLite3Stmt::getClass()};
359 SQLite3Stmt *stmt = Native::data<SQLite3Stmt>(ret);
360 HHVM_MN(SQLite3Stmt, __construct)(ret.get(), Object{this_}, sql);
361 if (stmt->m_raw_stmt) {
362 return ret;
365 return false;
368 Variant HHVM_METHOD(SQLite3, query,
369 const String& sql) {
370 auto *data = Native::data<SQLite3>(this_);
371 SYNC_VM_REGS_SCOPED();
372 data->validate();
373 if (!sql.empty()) {
374 Variant stmt = HHVM_MN(SQLite3, prepare)(this_, sql);
375 if (!same(stmt, false)) {
376 Object obj_stmt = stmt.toObject();
377 assertx(obj_stmt.instanceof(SQLite3Stmt::getClass()));
378 return HHVM_MN(SQLite3Stmt, execute)(obj_stmt.get());
381 return false;
384 Variant HHVM_METHOD(SQLite3, querysingle,
385 const String& sql,
386 bool entire_row /* = false */) {
387 auto *data = Native::data<SQLite3>(this_);
388 SYNC_VM_REGS_SCOPED();
389 data->validate();
390 if (!sql.empty()) {
391 Variant stmt = HHVM_MN(SQLite3, prepare)(this_, sql);
392 if (!same(stmt, false)) {
393 Object obj_stmt = stmt.toObject();
394 assertx(obj_stmt.instanceof(SQLite3Stmt::getClass()));
395 sqlite3_stmt *pstmt =
396 Native::data<SQLite3Stmt>(obj_stmt)->m_raw_stmt;
397 switch (sqlite3_step(pstmt)) {
398 case SQLITE_ROW: /* Valid Row */
399 if (entire_row) {
400 Array ret = Array::Create();
401 for (int i = 0; i < sqlite3_data_count(pstmt); i++) {
402 ret.set(String((char*)sqlite3_column_name(pstmt, i), CopyString),
403 get_column_value(pstmt, i));
405 return ret;
407 return get_column_value(pstmt, 0);
408 case SQLITE_DONE: /* Valid but no results */
409 if (entire_row) {
410 return empty_array();
411 } else {
412 return init_null();
414 default:
415 raise_warning("Unable to execute statement: %s",
416 sqlite3_errmsg(data->m_raw_db));
420 return false;
423 bool HHVM_METHOD(SQLite3, createfunction,
424 const String& name,
425 const Variant& callback,
426 int64_t argcount /* = -1 */) {
427 auto *data = Native::data<SQLite3>(this_);
428 data->validate();
429 if (name.empty()) {
430 return false;
432 if (!is_callable(callback)) {
433 raise_warning("Not a valid callback function %s",
434 callback.toString().data());
435 return false;
438 auto udf = req::make_shared<SQLite3::UserDefinedFunc>();
439 if (sqlite3_create_function(data->m_raw_db, name.data(), argcount,
440 SQLITE_UTF8, udf.get(), php_sqlite3_callback_func,
441 nullptr, nullptr) == SQLITE_OK) {
442 udf->func = callback;
443 udf->argc = argcount;
444 data->m_udfs.push_back(udf);
445 return true;
447 return false;
450 bool HHVM_METHOD(SQLite3, createaggregate,
451 const String& name,
452 const Variant& step,
453 const Variant& final,
454 int64_t argcount /* = -1 */) {
455 auto *data = Native::data<SQLite3>(this_);
456 data->validate();
457 if (name.empty()) {
458 return false;
460 if (!is_callable(step)) {
461 raise_warning("Not a valid callback function %s",
462 step.toString().data());
463 return false;
465 if (!is_callable(final)) {
466 raise_warning("Not a valid callback function %s",
467 final.toString().data());
468 return false;
471 auto udf = req::make_shared<SQLite3::UserDefinedFunc>();
472 if (sqlite3_create_function(data->m_raw_db, name.data(), argcount,
473 SQLITE_UTF8, udf.get(), nullptr,
474 php_sqlite3_callback_step,
475 php_sqlite3_callback_final) == SQLITE_OK) {
476 udf->step = step;
477 udf->fini = final;
478 udf->argc = argcount;
479 data->m_udfs.push_back(udf);
480 return true;
482 return false;
485 bool HHVM_METHOD(SQLite3, openblob, const String& /*table*/,
486 const String& /*column*/, int64_t /*rowid*/,
487 const Variant& /*dbname*/ /* = null */) {
488 throw_not_supported(__func__, "sqlite3 stream");
491 ///////////////////////////////////////////////////////////////////////////////
493 Class *SQLite3Stmt::s_class = nullptr;
494 const StaticString SQLite3Stmt::s_className("SQLite3Stmt");
496 IMPLEMENT_GET_CLASS(SQLite3Stmt)
498 SQLite3Stmt::SQLite3Stmt() : m_raw_stmt(nullptr) {
501 SQLite3Stmt::~SQLite3Stmt() {
502 if (m_raw_stmt) {
503 sqlite3_finalize(m_raw_stmt);
507 void HHVM_METHOD(SQLite3Stmt, __construct,
508 const Object& dbobject,
509 const String& statement) {
510 auto *data = Native::data<SQLite3Stmt>(this_);
511 if (!statement.empty()) {
512 assertx(dbobject.instanceof(SQLite3::getClass()));
513 const SQLite3 *db = Native::data<SQLite3>(dbobject);
514 db->validate();
515 data->m_db = dbobject;
517 int errcode = sqlite3_prepare_v2(db->m_raw_db, statement.data(),
518 statement.size(), &data->m_raw_stmt,
519 nullptr);
520 if (errcode != SQLITE_OK) {
521 raise_warning("Unable to prepare statement: %d, %s",
522 errcode, sqlite3_errmsg(db->m_raw_db));
527 void SQLite3Stmt::validate() const {
528 if (!m_raw_stmt) {
529 SystemLib::throwExceptionObject("SQLite3Stmt object was not initialized");
533 int64_t HHVM_METHOD(SQLite3Stmt, paramcount) {
534 auto *data = Native::data<SQLite3Stmt>(this_);
535 data->validate();
536 return sqlite3_bind_parameter_count(data->m_raw_stmt);
539 bool HHVM_METHOD(SQLite3Stmt, close) {
540 auto *data = Native::data<SQLite3Stmt>(this_);
541 if (data->m_raw_stmt) {
542 sqlite3_finalize(data->m_raw_stmt);
543 data->m_raw_stmt = nullptr;
545 return true;
548 bool HHVM_METHOD(SQLite3Stmt, reset) {
549 auto *data = Native::data<SQLite3Stmt>(this_);
550 data->validate();
551 if (sqlite3_reset(data->m_raw_stmt) != SQLITE_OK) {
552 raise_warning("Unable to reset statement: %s",
553 sqlite3_errmsg(sqlite3_db_handle(data->m_raw_stmt)));
554 return false;
556 return true;
559 bool HHVM_METHOD(SQLite3Stmt, clear) {
560 auto *data = Native::data<SQLite3Stmt>(this_);
561 data->validate();
562 if (sqlite3_clear_bindings(data->m_raw_stmt) != SQLITE_OK) {
563 raise_warning("Unable to clear statement: %s",
564 sqlite3_errmsg(sqlite3_db_handle(data->m_raw_stmt)));
565 return false;
567 data->m_bound_params.clear();
568 return true;
571 bool HHVM_METHOD(SQLite3Stmt, bindparam,
572 const Variant& name,
573 VRefParam parameter,
574 int64_t type /* = SQLITE3_TEXT */) {
575 auto *data = Native::data<SQLite3Stmt>(this_);
576 auto param = req::make_shared<SQLite3Stmt::BoundParam>();
577 param->type = type;
578 param->value.setWithRef(parameter);
580 if (name.isString()) {
581 String sname = name.toString();
582 if (sname.charAt(0) != ':') {
583 /* We need a : prefix to resolve a name to a parameter number */
584 sname = String(":") + sname;
586 param->index = sqlite3_bind_parameter_index(data->m_raw_stmt, sname.data());
587 } else {
588 param->index = name.toInt64();
590 if (param->index < 1) {
591 return false;
594 data->m_bound_params.push_back(param);
595 return true;
598 bool HHVM_METHOD(SQLite3Stmt, bindvalue,
599 const Variant& name,
600 const Variant& parameter,
601 int64_t type /* = SQLITE3_TEXT */) {
602 Variant v = parameter;
603 return HHVM_MN(SQLite3Stmt, bindparam)(this_, name, v, type);
606 Variant HHVM_METHOD(SQLite3Stmt, execute) {
607 auto *data = Native::data<SQLite3Stmt>(this_);
608 SYNC_VM_REGS_SCOPED();
609 data->validate();
611 for (unsigned int i = 0; i < data->m_bound_params.size(); i++) {
612 SQLite3Stmt::BoundParam &p = *data->m_bound_params[i];
613 if (p.value.isNull()) {
614 sqlite3_bind_null(data->m_raw_stmt, p.index);
615 continue;
618 switch (p.type) {
619 case SQLITE_INTEGER:
620 sqlite3_bind_int(data->m_raw_stmt, p.index, p.value.toInt64());
621 break;
622 case SQLITE_FLOAT:
623 sqlite3_bind_double(data->m_raw_stmt, p.index, p.value.toDouble());
624 break;
625 case SQLITE_BLOB:
627 String sblob;
628 if (p.value.isResource()) {
629 Variant blob = HHVM_FN(stream_get_contents)(p.value.toResource());
630 if (same(blob, false)) {
631 raise_warning("Unable to read stream for parameter %d",
632 p.index);
633 return false;
635 sblob = blob.toString();
636 } else {
637 sblob = p.value.toString();
639 sqlite3_bind_blob(data->m_raw_stmt, p.index, sblob.data(), sblob.size(),
640 SQLITE_TRANSIENT);
641 break;
643 case SQLITE3_TEXT:
645 String stext = p.value.toString();
646 sqlite3_bind_text(data->m_raw_stmt, p.index, stext.data(), stext.size(),
647 SQLITE_STATIC);
648 break;
650 case SQLITE_NULL:
651 sqlite3_bind_null(data->m_raw_stmt, p.index);
652 break;
653 default:
654 raise_warning("Unknown parameter type: %d for parameter %d",
655 p.type, p.index);
656 return false;
660 switch (sqlite3_step(data->m_raw_stmt)) {
661 case SQLITE_ROW: /* Valid Row */
662 case SQLITE_DONE: /* Valid but no results */
664 sqlite3_reset(data->m_raw_stmt);
665 Object ret{SQLite3Result::getClass()};
666 SQLite3Result *result = Native::data<SQLite3Result>(ret);
667 result->m_stmt_obj = Object(this_);
668 result->m_stmt = data;
669 return ret;
671 case SQLITE_ERROR:
672 sqlite3_reset(data->m_raw_stmt);
673 // fall through
674 default:
675 raise_warning("Unable to execute statement: %s",
676 sqlite3_errmsg(sqlite3_db_handle(data->m_raw_stmt)));
678 return false;
681 ///////////////////////////////////////////////////////////////////////////////
683 Class *SQLite3Result::s_class = nullptr;
684 const StaticString SQLite3Result::s_className("SQLite3Result");
686 IMPLEMENT_GET_CLASS(SQLite3Result)
688 SQLite3Result::SQLite3Result() : m_stmt(nullptr) {
691 void SQLite3Result::validate() const {
692 if (!m_stmt) {
693 SystemLib::throwExceptionObject("SQLite3Result object was not initialized");
695 m_stmt->validate();
698 int64_t HHVM_METHOD(SQLite3Result, numcolumns) {
699 auto *data = Native::data<SQLite3Result>(this_);
700 data->validate();
701 return sqlite3_column_count(data->m_stmt->m_raw_stmt);
704 String HHVM_METHOD(SQLite3Result, columnname,
705 int64_t column) {
706 auto *data = Native::data<SQLite3Result>(this_);
707 data->validate();
708 return String((char*)sqlite3_column_name(data->m_stmt->m_raw_stmt, column),
709 CopyString);
712 int64_t HHVM_METHOD(SQLite3Result, columntype,
713 int64_t column) {
714 auto *data = Native::data<SQLite3Result>(this_);
715 data->validate();
716 return sqlite3_column_type(data->m_stmt->m_raw_stmt, column);
719 Variant HHVM_METHOD(SQLite3Result, fetcharray,
720 int64_t mode /* = SQLITE3_BOTH */) {
721 auto *data = Native::data<SQLite3Result>(this_);
722 SYNC_VM_REGS_SCOPED();
723 data->validate();
725 switch (sqlite3_step(data->m_stmt->m_raw_stmt)) {
726 case SQLITE_ROW:
727 if (mode & PHP_SQLITE3_BOTH) {
728 Array ret = Array::Create();
729 for (int i = 0; i < sqlite3_data_count(data->m_stmt->m_raw_stmt); i++) {
730 Variant value = get_column_value(data->m_stmt->m_raw_stmt, i);
731 if (mode & PHP_SQLITE3_NUM) {
732 ret.set(i, value);
734 if (mode & PHP_SQLITE3_ASSOC) {
735 ret.set(HHVM_MN(SQLite3Result, columnname)(this_, i), value);
738 return ret;
740 break;
741 case SQLITE_DONE:
742 return false;
743 default:
744 raise_warning("Unable to execute statement: %s",
745 sqlite3_errmsg(sqlite3_db_handle(data->m_stmt->m_raw_stmt)));
747 return init_null();
750 bool HHVM_METHOD(SQLite3Result, reset) {
751 auto *data = Native::data<SQLite3Result>(this_);
752 data->validate();
753 return sqlite3_reset(data->m_stmt->m_raw_stmt) == SQLITE_OK;
756 bool HHVM_METHOD(SQLite3Result, finalize) {
757 auto *data = Native::data<SQLite3Result>(this_);
758 data->validate();
759 data->m_stmt_obj.reset();
760 data->m_stmt = nullptr;
761 return true;
764 ///////////////////////////////////////////////////////////////////////////////
766 static struct SQLite3Extension final : Extension {
767 SQLite3Extension() : Extension("sqlite3", "0.7-dev") {}
768 void moduleInit() override {
769 HHVM_RC_INT(SQLITE3_ASSOC, PHP_SQLITE3_ASSOC);
770 HHVM_RC_INT(SQLITE3_NUM, PHP_SQLITE3_NUM);
771 HHVM_RC_INT(SQLITE3_BOTH, PHP_SQLITE3_BOTH);
773 HHVM_RC_INT(SQLITE3_INTEGER, SQLITE_INTEGER);
774 HHVM_RC_INT(SQLITE3_FLOAT, SQLITE_FLOAT);
775 HHVM_RC_INT_SAME(SQLITE3_TEXT);
776 HHVM_RC_INT(SQLITE3_BLOB, SQLITE_BLOB);
777 HHVM_RC_INT(SQLITE3_NULL, SQLITE_NULL);
778 HHVM_RC_INT(SQLITE3_OPEN_READONLY, SQLITE_OPEN_READONLY);
779 HHVM_RC_INT(SQLITE3_OPEN_READWRITE, SQLITE_OPEN_READWRITE);
780 HHVM_RC_INT(SQLITE3_OPEN_CREATE, SQLITE_OPEN_CREATE);
782 HHVM_ME(SQLite3, __construct);
783 HHVM_ME(SQLite3, open);
784 HHVM_ME(SQLite3, busytimeout);
785 HHVM_ME(SQLite3, close);
786 HHVM_ME(SQLite3, exec);
787 HHVM_ME(SQLite3, lastinsertrowid);
788 HHVM_ME(SQLite3, lasterrorcode);
789 HHVM_ME(SQLite3, lasterrormsg);
790 HHVM_ME(SQLite3, loadextension);
791 HHVM_ME(SQLite3, changes);
792 HHVM_ME(SQLite3, prepare);
793 HHVM_ME(SQLite3, query);
794 HHVM_ME(SQLite3, querysingle);
795 HHVM_ME(SQLite3, createfunction);
796 HHVM_ME(SQLite3, createaggregate);
797 HHVM_ME(SQLite3, openblob);
798 HHVM_STATIC_ME(SQLite3, version);
799 HHVM_STATIC_ME(SQLite3, escapestring);
800 Native::registerNativeDataInfo<SQLite3>(SQLite3::s_className.get(),
801 Native::NDIFlags::NO_SWEEP);
803 HHVM_ME(SQLite3Stmt, __construct);
804 HHVM_ME(SQLite3Stmt, paramcount);
805 HHVM_ME(SQLite3Stmt, close);
806 HHVM_ME(SQLite3Stmt, reset);
807 HHVM_ME(SQLite3Stmt, clear);
808 HHVM_ME(SQLite3Stmt, bindparam);
809 HHVM_ME(SQLite3Stmt, bindvalue);
810 HHVM_ME(SQLite3Stmt, execute);
811 Native::registerNativeDataInfo<SQLite3Stmt>(SQLite3Stmt::s_className.get(),
812 Native::NDIFlags::NO_SWEEP);
814 HHVM_ME(SQLite3Result, numcolumns);
815 HHVM_ME(SQLite3Result, columnname);
816 HHVM_ME(SQLite3Result, columntype);
817 HHVM_ME(SQLite3Result, fetcharray);
818 HHVM_ME(SQLite3Result, reset);
819 HHVM_ME(SQLite3Result, finalize);
820 Native::registerNativeDataInfo<SQLite3Result>(
821 SQLite3Result::s_className.get(), Native::NDIFlags::NO_SWEEP);
823 loadSystemlib();
825 } s_sqlite3_extension;
827 ///////////////////////////////////////////////////////////////////////////////