Release the HHVM async mysql extension
[hiphop-php.git] / hphp / runtime / ext / async_mysql / ext_async_mysql.cpp
blob4483ad9e91705f96b4ae56963eeb90adf860dfcb
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "ext_async_mysql.h"
19 #include <algorithm>
20 #include <memory>
21 #include <vector>
23 #include <squangle/mysql_client/AsyncHelpers.h>
25 #include "hphp/runtime/base/array-init.h"
26 #include "hphp/runtime/ext/ext_collections.h"
27 #include "hphp/runtime/ext/mysql/ext_mysql.h"
28 #include "hphp/runtime/ext/mysql/mysql_common.h"
29 #include "hphp/runtime/vm/native-data.h"
30 #include "hphp/system/systemlib.h"
31 #include "hphp/util/logger.h"
33 namespace HPHP {
34 ///////////////////////////////////////////////////////////////////////////////
36 #define DEFINE_CONSTANT(name) \
37 const int64_t k_##name = name; \
38 const StaticString s_##name(#name); \
40 #define IMPLEMENT_GET_CLASS(cls) \
41 Class* cls::getClass() { \
42 if (s_class == nullptr) { \
43 s_class = Unit::lookupClass(s_className.get()); \
44 assert(s_class); \
45 } \
46 return s_class; \
47 } \
49 // expose the mysql flags
50 DEFINE_CONSTANT(NOT_NULL_FLAG);
51 DEFINE_CONSTANT(PRI_KEY_FLAG);
52 DEFINE_CONSTANT(UNIQUE_KEY_FLAG);
53 DEFINE_CONSTANT(MULTIPLE_KEY_FLAG);
54 DEFINE_CONSTANT(UNSIGNED_FLAG);
55 DEFINE_CONSTANT(ZEROFILL_FLAG);
56 DEFINE_CONSTANT(BINARY_FLAG);
57 DEFINE_CONSTANT(AUTO_INCREMENT_FLAG);
58 DEFINE_CONSTANT(ENUM_FLAG);
59 DEFINE_CONSTANT(SET_FLAG);
60 DEFINE_CONSTANT(BLOB_FLAG);
61 DEFINE_CONSTANT(TIMESTAMP_FLAG);
62 DEFINE_CONSTANT(NUM_FLAG);
63 DEFINE_CONSTANT(NO_DEFAULT_VALUE_FLAG);
65 // expose the mysql field types
66 DEFINE_CONSTANT(MYSQL_TYPE_TINY);
67 DEFINE_CONSTANT(MYSQL_TYPE_SHORT);
68 DEFINE_CONSTANT(MYSQL_TYPE_LONG);
69 DEFINE_CONSTANT(MYSQL_TYPE_INT24);
70 DEFINE_CONSTANT(MYSQL_TYPE_LONGLONG);
71 DEFINE_CONSTANT(MYSQL_TYPE_DECIMAL);
72 DEFINE_CONSTANT(MYSQL_TYPE_NEWDECIMAL);
73 DEFINE_CONSTANT(MYSQL_TYPE_FLOAT);
74 DEFINE_CONSTANT(MYSQL_TYPE_DOUBLE);
75 DEFINE_CONSTANT(MYSQL_TYPE_BIT);
76 DEFINE_CONSTANT(MYSQL_TYPE_TIMESTAMP);
77 DEFINE_CONSTANT(MYSQL_TYPE_DATE);
78 DEFINE_CONSTANT(MYSQL_TYPE_TIME);
79 DEFINE_CONSTANT(MYSQL_TYPE_DATETIME);
80 DEFINE_CONSTANT(MYSQL_TYPE_YEAR);
81 DEFINE_CONSTANT(MYSQL_TYPE_STRING);
82 DEFINE_CONSTANT(MYSQL_TYPE_VAR_STRING);
83 DEFINE_CONSTANT(MYSQL_TYPE_BLOB);
84 DEFINE_CONSTANT(MYSQL_TYPE_SET);
85 DEFINE_CONSTANT(MYSQL_TYPE_ENUM);
86 DEFINE_CONSTANT(MYSQL_TYPE_GEOMETRY);
87 DEFINE_CONSTANT(MYSQL_TYPE_NULL);
89 static am::AsyncMysqlClient* getDefaultClient() {
90 return am::AsyncMysqlClient::defaultClient();
93 void HHVM_STATIC_METHOD(AsyncMysqlClient, setPoolsConnectionLimit,
94 int64_t limit) {
95 getDefaultClient()->setPoolsConnectionLimit(limit);
98 Object HHVM_STATIC_METHOD(AsyncMysqlClient, connect,
99 const String& host,
100 int port,
101 const String& dbname,
102 const String& user,
103 const String& password,
104 int64_t timeout_micros /* = -1 */) {
105 auto op = getDefaultClient()->beginConnection(static_cast<std::string>(host),
106 port,
107 static_cast<std::string>(dbname),
108 static_cast<std::string>(user),
109 static_cast<std::string>(password));
110 if (timeout_micros < 0) {
111 timeout_micros = mysqlExtension::ConnectTimeout * 1000;
113 if (timeout_micros > 0) {
114 op->setTimeout(am::Duration(timeout_micros));
117 auto event = new AsyncMysqlConnectEvent(op);
118 try {
119 op->setCallback([event](am::ConnectOperation& op) { event->opFinished(); });
120 op->run();
122 return event->getWaitHandle();
124 catch (...) {
125 assert(false);
126 event->abandon();
127 return nullptr;
131 Object HHVM_STATIC_METHOD(AsyncMysqlClient, adoptConnection,
132 const Variant& connection) {
133 auto conn = connection.toResource().getTyped<MySQLResource>()->mysql();
134 // mysql connection from ext/mysql/mysql_common.h
135 auto raw_conn = conn->eject_mysql();
136 auto adopted = getDefaultClient()->adoptConnection(raw_conn,
137 conn->m_host,
138 conn->m_port,
139 conn->m_database,
140 conn->m_username,
141 conn->m_password);
143 ObjectData* ret = AsyncMysqlConnection::newInstance(std::move(adopted));
144 return Object(ret);
147 ///////////////////////////////////////////////////////////////////////////////
148 // class AsyncMysqlConnectionPool
150 const StaticString AsyncMysqlConnectionPool::s_className(
151 "AsyncMysqlConnectionPool");
153 // `connection_limit` - Defines the limit of opened connections for each set of
154 // User, Database, Host, etc
155 // `total_connection_limit` - Defines the total limit of opened connection as a
156 // whole
157 // `idle_timeout_micros` - Sets the maximum idle time in microseconds a
158 // connection can be left in the pool without being killed by the pool
159 // `age_timeout_micros` - Sets the maximum age (means the time since started) of
160 // a connection, the pool will then kill this connection when reaches that limit
161 // `expiration_policy` - We offer 2 policies for the expiration of a
162 // connection: `IdleTime` and `Age`, in the Idle policy a connection will only
163 // die after some time being idle; in Age policy we extend the idle one to kill
164 // also by age
166 const StaticString s_per_key_connection_limit("per_key_connection_limit"),
167 s_pool_connection_limit("pool_connection_limit"),
168 s_idle_timeout_micros("idle_timeout_micros"),
169 s_age_timeout_micros("age_timeout_micros"),
170 s_expiration_policy("expiration_policy");
172 void HHVM_METHOD(AsyncMysqlConnectionPool, __construct,
173 const Array& options) {
175 auto* data = Native::data<AsyncMysqlConnectionPool>(this_);
176 am::PoolOptions pool_options;
177 if (options.exists(s_per_key_connection_limit)) {
178 pool_options.setPerKeyLimit(options[s_per_key_connection_limit].toInt32());
180 if (options.exists(s_pool_connection_limit)) {
181 pool_options.setPoolLimit(options[s_pool_connection_limit].toInt32());
183 if (options.exists(s_idle_timeout_micros)) {
184 pool_options.setIdleTimeout(
185 am::Duration(options[s_idle_timeout_micros].toInt64()));
187 if (options.exists(s_age_timeout_micros)) {
188 pool_options.setAgeTimeout(
189 am::Duration(options[s_age_timeout_micros].toInt64()));
191 if (options.exists(s_expiration_policy)) {
192 pool_options.setExpPolicy(options[s_expiration_policy].toString() ==
193 String::FromCStr("IdleTime")
194 ? am::ExpirationPolicy::IdleTime
195 : am::ExpirationPolicy::Age);
197 data->m_async_pool = am::AsyncConnectionPool::makePool(
198 getDefaultClient(), pool_options);
201 // `created_pool_connections` - Number of connections created by the pool
202 // `destroyed_pool_connections` - Number of connections destroyed by the pool,
203 // be careful with this number, it will only be equal to the above when all
204 // created connections have been close. This may not be true by the end of
205 // a request.
206 // `connections_requested` - This number helps with comparing how many
207 // connection would have been made if the there were no pooling.
208 // `pool_hits` - Counts the number of times a request for connection went to
209 // the pool and it had a connection ready in cache
210 // `pool_misses` - Counts the number of times a we needed a connection and
211 // none was ready to return
212 const StaticString s_created_pool_connections("created_pool_connections"),
213 s_destroyed_pool_connections("destroyed_pool_connections"),
214 s_connections_requested("connections_requested"), s_pool_hits("pool_hits"),
215 s_pool_misses("pool_misses");
217 Array HHVM_METHOD(AsyncMysqlConnectionPool, getPoolStats) {
218 auto* data = Native::data<AsyncMysqlConnectionPool>(this_);
219 auto* pool_stats = data->m_async_pool->stats();
220 Array ret = make_map_array(s_created_pool_connections,
221 pool_stats->numCreatedPoolConnections(),
222 s_destroyed_pool_connections,
223 pool_stats->numDestroyedPoolConnections(),
224 s_connections_requested,
225 pool_stats->numConnectionsRequested(),
226 s_pool_hits,
227 pool_stats->numPoolHits(),
228 s_pool_misses,
229 pool_stats->numPoolMisses());
230 return ret;
233 Object HHVM_METHOD(AsyncMysqlConnectionPool, connect,
234 const String& host,
235 int port,
236 const String& dbname,
237 const String& user,
238 const String& password,
239 int64_t timeout_micros,
240 const String& extra_key) {
242 auto* data = Native::data<AsyncMysqlConnectionPool>(this_);
243 auto op = data->m_async_pool->beginConnection(static_cast<std::string>(host),
244 port,
245 static_cast<std::string>(dbname),
246 static_cast<std::string>(user),
247 static_cast<std::string>(password),
248 static_cast<std::string>(extra_key));
249 if (timeout_micros < 0) {
250 timeout_micros = mysqlExtension::ConnectTimeout * 1000;
252 if (timeout_micros > 0) {
253 op->setTimeout(am::Duration(timeout_micros));
256 auto event = new AsyncMysqlConnectEvent(op);
257 try {
258 op->setCallback([event](am::ConnectOperation& op) { event->opFinished(); });
259 op->run();
261 return event->getWaitHandle();
263 catch (...) {
264 LOG(ERROR) << "Unexpected exception while beginning ConnectPoolOperation";
265 assert(false);
266 event->abandon();
267 return nullptr;
271 ///////////////////////////////////////////////////////////////////////////////
272 // class AsyncMysqlConnection
274 Class* AsyncMysqlConnection::s_class = nullptr;
275 const StaticString AsyncMysqlConnection::s_className("AsyncMysqlConnection");
277 IMPLEMENT_GET_CLASS(AsyncMysqlConnection)
279 ObjectData* AsyncMysqlConnection::newInstance(
280 std::unique_ptr<am::Connection> conn) {
281 ObjectData* ret = ObjectData::newInstance(getClass());
282 Native::data<AsyncMysqlConnection>(ret)->setConnection(std::move(conn));
283 return ret;
286 AsyncMysqlConnection::AsyncMysqlConnection() : m_port(0), m_closed(false) {}
288 void AsyncMysqlConnection::sweep() {
289 m_conn.reset();
292 void AsyncMysqlConnection::setConnection(std::unique_ptr<am::Connection> conn) {
293 m_conn = std::move(conn);
294 m_host = String(m_conn->host(), CopyString);
295 m_port = m_conn->port();
298 void AsyncMysqlConnection::verifyValidConnection() {
299 if (UNLIKELY(!m_conn || !m_conn->ok())) {
300 if (m_closed) {
301 throw Object(SystemLib::AllocInvalidArgumentExceptionObject(
302 "attempt to invoke method on a closed connection"));
303 } else if (m_conn && !m_conn->ok()) {
304 throw Object(SystemLib::AllocInvalidArgumentExceptionObject(
305 "attempt to invoke method on an invalid connection"));
306 } else {
307 throw Object(SystemLib::AllocInvalidArgumentExceptionObject(
308 "attempt to invoke method on a busy connection"));
313 Object AsyncMysqlConnection::query(
314 ObjectData* this_,
315 am::Query query,
316 int64_t timeout_micros /* = -1 */) {
318 verifyValidConnection();
319 auto op = am::Connection::beginQuery(std::move(m_conn), query);
320 if (timeout_micros < 0) {
321 timeout_micros = mysqlExtension::ReadTimeout * 1000;
323 if (timeout_micros > 0) {
324 op->setTimeout(am::Duration(timeout_micros));
327 auto event = new AsyncMysqlQueryEvent(this_, op);
328 try {
329 am::QueryAppenderCallback appender_callback = [event](
330 am::QueryOperation& op,
331 am::QueryResult query_result,
332 am::QueryCallbackReason reason) {
333 DCHECK(reason != am::QueryCallbackReason::RowsFetched);
334 if (!op.done()) {
335 LOG(ERROR) << "Invalid state! Callback called as finished "
336 << "but operation didn't finish";
338 op.setQueryResult(std::move(query_result));
339 event->opFinished();
341 op->setCallback(am::resultAppender(appender_callback));
342 op->run();
344 return event->getWaitHandle();
346 catch (...) {
347 LOG(ERROR) << "Unexpected exception while beginning ConnectOperation";
348 assert(false);
349 event->abandon();
350 return nullptr;
354 Object HHVM_METHOD(AsyncMysqlConnection, query,
355 const String& query,
356 int64_t timeout_micros /* = -1 */) {
357 auto* data = Native::data<AsyncMysqlConnection>(this_);
359 return data->query(
360 this_,
361 am::Query::unsafe(static_cast<std::string>(query)),
362 timeout_micros);
365 Object HHVM_METHOD(AsyncMysqlConnection, queryf,
366 const String& pattern,
367 const Array& args) {
368 auto* data = Native::data<AsyncMysqlConnection>(this_);
370 // Not directly calling argsv.toFollyDynamic() as that creates a folly
371 // dynamic object, not list
372 std::vector<am::QueryArgument> query_args;
373 for (ArrayIter iter(args); iter; ++iter) {
374 const Variant& arg = iter.second();
375 // not using switch (arg.getType()) because null and strings are special
376 if (arg.isInteger()) {
377 query_args.push_back(arg.toInt64());
378 } else if (arg.isDouble()) {
379 query_args.push_back(arg.toDouble());
380 } else if (arg.isString()) {
381 query_args.push_back(static_cast<std::string>(arg.toString()));
382 } else if (arg.isNull()) {
383 query_args.push_back(am::QueryArgument());
384 } else {
385 throw_invalid_argument(
386 "queryf parameters must be scalars - parameter %ld is a %s",
387 query_args.size(),
388 getDataTypeString(arg.getType()).c_str()
393 return data->query(
394 this_,
395 am::Query(static_cast<std::string>(pattern), query_args));
398 Object HHVM_METHOD(AsyncMysqlConnection, multiQuery,
399 const Array& queries,
400 int64_t timeout_micros /* = -1 */) {
401 auto* data = Native::data<AsyncMysqlConnection>(this_);
403 data->verifyValidConnection();
404 std::vector<am::Query> queries_vec;
405 queries_vec.reserve(queries.size());
406 for (ArrayIter iter(queries); iter; ++iter) {
407 queries_vec.emplace_back(am::Query::unsafe(
408 static_cast<std::string>(iter.second().toString().data())));
410 auto op = am::Connection::beginMultiQuery(std::move(data->m_conn),
411 std::move(queries_vec));
412 if (timeout_micros < 0) {
413 timeout_micros = mysqlExtension::ReadTimeout * 1000;
415 if (timeout_micros > 0) {
416 op->setTimeout(am::Duration(timeout_micros));
419 auto event = new AsyncMysqlMultiQueryEvent(this_, op);
420 try {
421 am::MultiQueryAppenderCallback appender_callback = [event](
422 am::MultiQueryOperation& op,
423 std::vector<am::QueryResult> query_results,
424 am::QueryCallbackReason reason) {
425 DCHECK(reason != am::QueryCallbackReason::RowsFetched);
426 DCHECK(reason != am::QueryCallbackReason::QueryBoundary);
427 if (!op.done()) {
428 LOG(ERROR) << "Invalid state! Callback called as finished "
429 << "but operation didn't finish";
431 op.setQueryResults(std::move(query_results));
432 event->opFinished();
434 op->setCallback(am::resultAppender(appender_callback));
435 op->run();
437 return event->getWaitHandle();
439 catch (...) {
440 assert(false);
441 event->abandon();
442 return nullptr;
446 String HHVM_METHOD(AsyncMysqlConnection, escapeString, const String& input) {
447 auto* data = Native::data<AsyncMysqlConnection>(this_);
449 String ret = data->m_conn->escapeString(input.data());
450 return ret;
453 String HHVM_METHOD(AsyncMysqlConnection, serverInfo) {
454 auto* data = Native::data<AsyncMysqlConnection>(this_);
456 String ret = "";
457 if (data->m_conn && !data->m_closed) {
458 ret = data->m_conn->serverInfo();
460 return ret;
463 int HHVM_METHOD(AsyncMysqlConnection, warningCount) {
464 auto* data = Native::data<AsyncMysqlConnection>(this_);
466 int count = 0;
467 if (data->m_conn && !data->m_closed) {
468 count = data->m_conn->warningCount();
470 return count;
473 String HHVM_METHOD(AsyncMysqlConnection, host) {
474 auto* data = Native::data<AsyncMysqlConnection>(this_);
475 return data->m_host;
478 int HHVM_METHOD(AsyncMysqlConnection, port) {
479 auto* data = Native::data<AsyncMysqlConnection>(this_);
480 return data->m_port;
483 void HHVM_METHOD(AsyncMysqlConnection, setReusable,
484 bool reusable) {
485 auto* data = Native::data<AsyncMysqlConnection>(this_);
487 if (data->m_conn) {
488 data->m_conn->setReusable(reusable);
489 } else {
490 LOG(ERROR) << "Accessing closed connection";
494 bool HHVM_METHOD(AsyncMysqlConnection, isReusable) {
495 auto* data = Native::data<AsyncMysqlConnection>(this_);
497 if (data->m_conn) {
498 return data->m_conn->isReusable();
499 } else {
500 LOG(ERROR) << "Accessing closed connection";
502 return false;
505 void HHVM_METHOD(AsyncMysqlConnection, close) {
506 auto* data = Native::data<AsyncMysqlConnection>(this_);
508 data->m_conn.reset();
509 data->m_closed = true;
512 Variant HHVM_METHOD(AsyncMysqlConnection, releaseConnection) {
513 auto* data = Native::data<AsyncMysqlConnection>(this_);
514 data->verifyValidConnection();
516 auto raw_connection = data->m_conn->stealMysql();
517 auto host = data->m_conn->host();
518 auto port = data->m_conn->port();
519 auto username = data->m_conn->user();
520 auto database = data->m_conn->database();
521 data->m_conn.reset();
522 data->m_closed = true;
523 return new MySQL(host.c_str(),
524 port,
525 username.c_str(),
527 database.c_str(),
528 raw_connection);
531 ///////////////////////////////////////////////////////////////////////////////
532 // class AsyncMysqlResult
534 int64_t AsyncMysqlResult::elapsedMicros() {
535 return op()->elapsed().count();
538 double AsyncMysqlResult::startTime() {
539 am::Duration d = std::chrono::duration_cast<std::chrono::microseconds>(
540 op()->startTime() - std::chrono::system_clock::from_time_t(0));
541 return d.count() / 1000.0 / 1000.0;
544 double AsyncMysqlResult::endTime() {
545 am::Duration d = std::chrono::duration_cast<std::chrono::microseconds>(
546 op()->endTime() - std::chrono::system_clock::from_time_t(0));
547 return d.count() / 1000.0 / 1000.0;
550 #define DEFINE_PROXY_METHOD(cls, method, type) \
551 type HHVM_METHOD(cls, method) { return Native::data<cls>(this_)->method(); } \
553 #define EXTENDS_ASYNC_MYSQL_RESULT(cls) \
554 DEFINE_PROXY_METHOD(cls, elapsedMicros, int64_t) \
555 DEFINE_PROXY_METHOD(cls, startTime, double) \
556 DEFINE_PROXY_METHOD(cls, endTime, double) \
558 ///////////////////////////////////////////////////////////////////////////////
559 // class AsyncMysqlErrorResult
561 Class* AsyncMysqlErrorResult::s_class = nullptr;
562 const StaticString AsyncMysqlErrorResult::s_className("AsyncMysqlErrorResult");
564 IMPLEMENT_GET_CLASS(AsyncMysqlErrorResult)
566 ObjectData* AsyncMysqlErrorResult::newInstance(
567 std::shared_ptr<am::Operation> op) {
568 ObjectData* ret = ObjectData::newInstance(getClass());
569 Native::data<AsyncMysqlErrorResult>(ret)->create(op);
570 return ret;
573 void AsyncMysqlErrorResult::create(std::shared_ptr<am::Operation> op) {
574 m_op = op;
577 void AsyncMysqlErrorResult::sweep() {
578 m_op.reset();
581 am::Operation* AsyncMysqlErrorResult::op() {
582 if (m_op.get() == nullptr) {
583 // m_op is null if this object is directly created. It is possible if
584 // a derived class is defined that does not call this class' constructor.
585 Object e(SystemLib::AllocInvalidOperationExceptionObject(
586 "AsyncMysqlErrorResult object is not properly initialized."));
587 throw e;
589 return m_op.get();
592 EXTENDS_ASYNC_MYSQL_RESULT(AsyncMysqlErrorResult)
594 int HHVM_METHOD(AsyncMysqlErrorResult, mysql_errno) {
595 auto* data = Native::data<AsyncMysqlErrorResult>(this_);
596 return data->m_op->mysql_errno();
599 String HHVM_METHOD(AsyncMysqlErrorResult, mysql_error) {
600 auto* data = Native::data<AsyncMysqlErrorResult>(this_);
601 return data->m_op->mysql_error();
604 String HHVM_METHOD(AsyncMysqlErrorResult, failureType) {
605 auto* data = Native::data<AsyncMysqlErrorResult>(this_);
606 return data->m_op->resultString().toString();
609 ///////////////////////////////////////////////////////////////////////////////
610 // class AsyncMysqlQueryErrorResult
612 Class* AsyncMysqlQueryErrorResult::s_class = nullptr;
613 const StaticString AsyncMysqlQueryErrorResult::s_className(
614 "AsyncMysqlQueryErrorResult");
616 IMPLEMENT_GET_CLASS(AsyncMysqlQueryErrorResult)
618 ObjectData* AsyncMysqlQueryErrorResult::newInstance(
619 std::shared_ptr<am::Operation> op, SmartPtr<c_Vector> results) {
620 ObjectData* ret = ObjectData::newInstance(getClass());
621 Native::data<AsyncMysqlQueryErrorResult>(ret)->create(op, results);
622 return ret;
625 AsyncMysqlQueryErrorResult::AsyncMysqlQueryErrorResult() {
626 static_assert(offsetof(AsyncMysqlQueryErrorResult, m_parent) +
627 sizeof(AsyncMysqlErrorResult) == sizeof(AsyncMysqlQueryErrorResult),
628 "m_parent must be the last member of AsyncMysqlQueryErrorResult");
631 void AsyncMysqlQueryErrorResult::sweep() {
632 m_parent.sweep();
635 void AsyncMysqlQueryErrorResult::create(std::shared_ptr<am::Operation> op,
636 SmartPtr<c_Vector> results) {
637 m_parent.create(op);
638 m_query_results = results;
641 int HHVM_METHOD(AsyncMysqlQueryErrorResult, numSuccessfulQueries) {
642 auto* data = Native::data<AsyncMysqlQueryErrorResult>(this_);
643 return std::dynamic_pointer_cast<am::FetchOperation>(data->m_parent.m_op)
644 ->numQueriesExecuted();
647 Object HHVM_METHOD(AsyncMysqlQueryErrorResult, getSuccessfulResults) {
648 auto* data = Native::data<AsyncMysqlQueryErrorResult>(this_);
649 return Object(data->m_query_results);
652 ///////////////////////////////////////////////////////////////////////////////
653 // class AsyncMysqlQueryResult
655 Class* AsyncMysqlQueryResult::s_class = nullptr;
656 const StaticString AsyncMysqlQueryResult::s_className("AsyncMysqlQueryResult");
658 IMPLEMENT_GET_CLASS(AsyncMysqlQueryResult)
660 void AsyncMysqlQueryResult::sweep() {
661 m_op.reset();
662 m_query_result.reset();
665 ObjectData* AsyncMysqlQueryResult::newInstance(
666 std::shared_ptr<am::Operation> op, am::QueryResult query_result) {
667 ObjectData* ret = ObjectData::newInstance(getClass());
668 Native::data<AsyncMysqlQueryResult>(ret)->create(op, std::move(query_result));
669 return ret;
672 void AsyncMysqlQueryResult::create(std::shared_ptr<am::Operation> op,
673 am::QueryResult query_result) {
674 m_op = op;
675 m_query_result =
676 folly::make_unique<am::QueryResult>(std::move(query_result));
677 m_field_index =
678 std::make_shared<FieldIndex>(m_query_result->getRowFields());
681 am::Operation* AsyncMysqlQueryResult::op() {
682 return m_op.get();
685 EXTENDS_ASYNC_MYSQL_RESULT(AsyncMysqlQueryResult)
687 int64_t HHVM_METHOD(AsyncMysqlQueryResult, lastInsertId) {
688 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
689 return data->m_query_result->lastInsertId();
692 int64_t HHVM_METHOD(AsyncMysqlQueryResult, numRowsAffected) {
693 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
694 return data->m_query_result->numRowsAffected();
697 int64_t HHVM_METHOD(AsyncMysqlQueryResult, numRows) {
698 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
699 return data->m_query_result->numRows();
701 Object HHVM_METHOD(AsyncMysqlQueryResult, vectorRows) {
702 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
703 return data->buildRows(false /* as_maps */, false /* typed */);
706 Object HHVM_METHOD(AsyncMysqlQueryResult, mapRows) {
707 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
708 return data->buildRows(true /* as_maps */, false /* typed */);
711 Object HHVM_METHOD(AsyncMysqlQueryResult, vectorRowsTyped) {
712 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
713 return data->buildRows(false /* as_maps */, true /* typed */);
716 Object HHVM_METHOD(AsyncMysqlQueryResult, mapRowsTyped) {
717 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
718 return data->buildRows(true /* as_maps */, true /* typed */);
721 Object HHVM_METHOD(AsyncMysqlQueryResult, rowBlocks) {
722 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
723 auto ret = makeSmartPtr<c_Vector>();
724 auto row_blocks = data->m_query_result->stealRows();
725 ret->reserve(row_blocks.size());
727 for (auto& row_block : row_blocks) {
728 ObjectData* row = AsyncMysqlRowBlock::newInstance(&row_block,
729 data->m_field_index);
730 ret->t_add(Object(row));
732 return Object(std::move(ret));
735 namespace {
736 Variant buildTypedValue(const am::RowFields* row_fields,
737 const am::Row& row,
738 int field_num,
739 bool typed_values) {
740 if (row.isNull(field_num)) {
741 return init_null();
744 // The underlying library may return zero length null ptr's to
745 // indicate an empty string (since the isNull check above would tell
746 // if it were actually NULL).
747 String string_value =
748 (row[field_num].data() == nullptr && row[field_num].size() == 0)
749 ? empty_string()
750 : String(row[field_num].data(), row[field_num].size(), CopyString);
752 if (!typed_values) {
753 return string_value;
756 return mysql_makevalue(string_value, row_fields->getFieldType(field_num));
760 Object AsyncMysqlQueryResult::buildRows(bool as_maps, bool typed_values) {
761 auto ret = makeSmartPtr<c_Vector>();
762 ret->reserve(m_query_result->numRows());
763 for (const auto& row : *m_query_result) {
764 if (as_maps) {
765 auto row_map = makeSmartPtr<c_Map>();
766 for (int i = 0; i < row.size(); ++i) {
767 row_map->t_set(
768 m_field_index->getFieldString(i),
769 buildTypedValue(
770 m_query_result->getRowFields(), row, i, typed_values));
772 ret->t_add(Variant(std::move(row_map)));
773 } else {
774 auto row_vector = makeSmartPtr<c_Vector>();
775 row_vector->reserve(row.size());
776 for (int i = 0; i < row.size(); ++i) {
777 row_vector->t_add(buildTypedValue(
778 m_query_result->getRowFields(), row, i, typed_values));
780 ret->t_add(Variant(std::move(row_vector)));
783 return Object(std::move(ret));
786 FieldIndex::FieldIndex(const am::RowFields* row_fields) {
787 if (row_fields == nullptr)
788 return;
789 field_names_.reserve(row_fields->numFields());
790 for (int i = 0; i < row_fields->numFields(); ++i) {
791 auto name = String(row_fields->fieldName(i).str());
792 field_names_.push_back(name);
793 field_name_map_[name] = i;
797 size_t FieldIndex::getFieldIndex(String field_name) const {
798 auto it = field_name_map_.find(field_name);
799 if (it == field_name_map_.end()) {
800 Object e(SystemLib::AllocInvalidArgumentExceptionObject(
801 "Given field name doesn't exist"));
802 throw e;
804 return it->second;
807 String FieldIndex::getFieldString(size_t field_index) const {
808 // Leaving out of bounds to be thrown by the vector in case needed
809 return field_names_.at(field_index);
812 namespace {
813 void throwAsyncMysqlException(const char* exception_type,
814 std::shared_ptr<am::Operation> op) {
815 ObjectData* error = AsyncMysqlErrorResult::newInstance(op);
817 assert(op->result() == am::OperationResult::Failed ||
818 op->result() == am::OperationResult::TimedOut ||
819 op->result() == am::OperationResult::Cancelled);
821 Array params;
822 params.append(error);
823 throw create_object(exception_type, params, true /* init */);
826 void throwAsyncMysqlQueryException(const char* exception_type,
827 std::shared_ptr<am::Operation> op,
828 SmartPtr<c_Vector> res) {
829 ObjectData* error = AsyncMysqlQueryErrorResult::newInstance(op, res);
831 assert(op->result() == am::OperationResult::Failed ||
832 op->result() == am::OperationResult::TimedOut ||
833 op->result() == am::OperationResult::Cancelled);
835 Array params;
836 params.append(error);
837 throw create_object(exception_type, params, true /* init */);
841 void AsyncMysqlConnectEvent::unserialize(Cell& result) {
842 if (m_op->ok()) {
843 ObjectData* ret = AsyncMysqlConnection::newInstance(
844 m_op->releaseConnection());
845 cellDup(make_tv<KindOfObject>(ret), result);
846 } else {
847 throwAsyncMysqlException("AsyncMysqlConnectException", m_op);
851 void AsyncMysqlQueryEvent::unserialize(Cell& result) {
852 // Retrieve the original conn and return the underlying connection
853 // to it.
854 assert(getPrivData()->instanceof(AsyncMysqlConnection::getClass()));
855 auto* conn = Native::data<AsyncMysqlConnection>(getPrivData());
856 conn->setConnection(m_query_op->releaseConnection());
858 if (m_query_op->ok()) {
859 auto query_result = m_query_op->stealQueryResult();
860 ObjectData* ret = AsyncMysqlQueryResult::newInstance(m_query_op,
861 std::move(query_result));
862 cellDup(make_tv<KindOfObject>(ret), result);
863 } else {
864 throwAsyncMysqlQueryException(
865 "AsyncMysqlQueryException",
866 m_query_op,
867 makeSmartPtr<c_Vector>());
871 void AsyncMysqlMultiQueryEvent::unserialize(Cell& result) {
872 // Same as unserialize from AsyncMysqlQueryEvent but the result is a
873 // vector of query results
874 assert(getPrivData()->instanceof(AsyncMysqlConnection::getClass()));
875 auto* conn = Native::data<AsyncMysqlConnection>(getPrivData());
876 conn->setConnection(m_multi_op->releaseConnection());
878 // Retrieving the results for all executed queries
879 auto results = makeSmartPtr<c_Vector>();
880 std::vector<am::QueryResult> query_results = m_multi_op->stealQueryResults();
881 results->reserve(query_results.size());
882 for (int i = 0; i < query_results.size(); ++i) {
883 ObjectData* ret = AsyncMysqlQueryResult::newInstance(m_multi_op,
884 std::move(query_results[i]));
885 results->t_add(ret);
887 query_results.clear();
889 if (m_multi_op->ok()) {
890 cellDup(make_tv<KindOfObject>(results.get()), result);
891 } else {
892 throwAsyncMysqlQueryException(
893 "AsyncMysqlQueryException", m_multi_op, results);
897 ///////////////////////////////////////////////////////////////////////////////
898 // class AsyncMysqlRowBlock
900 Class* AsyncMysqlRowBlock::s_class = nullptr;
901 const StaticString AsyncMysqlRowBlock::s_className("AsyncMysqlRowBlock");
903 IMPLEMENT_GET_CLASS(AsyncMysqlRowBlock)
905 ObjectData* AsyncMysqlRowBlock::newInstance(am::RowBlock* row_block,
906 std::shared_ptr<FieldIndex> indexer) {
907 ObjectData* ret = ObjectData::newInstance(AsyncMysqlRowBlock::getClass());
908 auto* data = Native::data<AsyncMysqlRowBlock>(ret);
909 data->m_row_block.reset(new am::RowBlock(std::move(*row_block)));
910 data->m_field_index = indexer;
911 return ret;
914 void AsyncMysqlRowBlock::sweep() {
915 m_row_block.reset();
918 size_t AsyncMysqlRowBlock::getIndexFromVariant(const Variant& field) {
919 if (field.isInteger()) {
920 return field.toInt64();
921 } else if (field.isString()) {
922 return m_field_index->getFieldIndex(field.toString());
924 Object e(SystemLib::AllocInvalidArgumentExceptionObject(
925 "Only integer or string field names may be used with RowBlock"));
926 throw e;
929 // The String conversion allows `NULL` to ""
930 template <>
931 folly::StringPiece AsyncMysqlRowBlock::getFieldAs(int64_t row,
932 const Variant& field) {
933 auto index = getIndexFromVariant(field);
934 try {
935 // Note that for String before you return to PHP you need to copy it into
936 // HPHP::String.
937 return m_row_block->getField<folly::StringPiece>(row, index);
939 catch (std::range_error& excep) {
940 Object e(SystemLib::AllocBadMethodCallExceptionObject(
941 std::string("Error during conversion: ") + excep.what()));
942 throw e;
946 template <typename FieldType>
947 FieldType AsyncMysqlRowBlock::getFieldAs(int64_t row, const Variant& field) {
948 auto index = getIndexFromVariant(field);
950 if (m_row_block->isNull(row, index)) {
951 Object e(SystemLib::AllocBadMethodCallExceptionObject(
952 "Field value needs to be non-null."));
953 throw e;
955 try {
956 return m_row_block->getField<FieldType>(row, index);
958 catch (std::range_error& excep) {
959 Object e(SystemLib::AllocBadMethodCallExceptionObject(
960 std::string("Error during conversion: ") + excep.what()));
961 throw e;
965 Variant HHVM_METHOD(AsyncMysqlRowBlock, at, int64_t row, const Variant& field) {
966 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
967 auto col_index = data->getIndexFromVariant(field);
968 return buildTypedValue(data->m_row_block->getRowFields(),
969 data->m_row_block->getRow(row),
970 col_index,
971 true);
974 int64_t HHVM_METHOD(AsyncMysqlRowBlock,
975 getFieldAsInt,
976 int64_t row,
977 const Variant& field) {
978 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
979 return data->getFieldAs<int64_t>(row, field);
982 double HHVM_METHOD(AsyncMysqlRowBlock,
983 getFieldAsDouble,
984 int64_t row,
985 const Variant& field) {
986 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
987 return data->getFieldAs<double>(row, field);
990 String HHVM_METHOD(AsyncMysqlRowBlock,
991 getFieldAsString,
992 int64_t row,
993 const Variant& field) {
994 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
995 auto val = data->getFieldAs<StringPiece>(row, field);
996 return StringData::Make(val.data(), val.size(), CopyString);
999 bool HHVM_METHOD(AsyncMysqlRowBlock, isNull,
1000 int64_t row,
1001 const Variant& field) {
1002 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1003 return data->m_row_block->isNull(row, data->getIndexFromVariant(field));
1006 int64_t HHVM_METHOD(AsyncMysqlRowBlock, fieldType,
1007 const Variant& field) {
1008 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1009 return data->m_row_block->getFieldType(data->getIndexFromVariant(field));
1012 int64_t HHVM_METHOD(AsyncMysqlRowBlock, fieldFlags,
1013 const Variant& field) {
1014 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1015 return data->m_row_block->getFieldFlags(data->getIndexFromVariant(field));
1018 String HHVM_METHOD(AsyncMysqlRowBlock, fieldName,
1019 int64_t field_id) {
1020 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1021 return data->m_field_index->getFieldString(field_id);
1024 bool HHVM_METHOD(AsyncMysqlRowBlock, isEmpty) {
1025 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1026 return data->m_row_block->empty();
1029 int64_t HHVM_METHOD(AsyncMysqlRowBlock, fieldsCount) {
1030 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1031 return data->m_row_block->numFields();
1034 int64_t HHVM_METHOD(AsyncMysqlRowBlock, count) {
1035 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1036 return data->m_row_block->numRows();
1039 Object HHVM_METHOD(AsyncMysqlRowBlock, getRow,
1040 int64_t row_no) {
1041 ObjectData* row = AsyncMysqlRow::newInstance(this_, row_no);
1042 return Object(row);
1045 Object HHVM_METHOD(AsyncMysqlRowBlock, getIterator) {
1046 ObjectData* it = AsyncMysqlRowBlockIterator::newInstance(this_, 0);
1047 return Object(it);
1050 ///////////////////////////////////////////////////////////////////////////////
1051 // class AsyncMysqlRowBlockIterator
1053 Class* AsyncMysqlRowBlockIterator::s_class = nullptr;
1054 const StaticString AsyncMysqlRowBlockIterator::s_className(
1055 "AsyncMysqlRowBlockIterator");
1057 IMPLEMENT_GET_CLASS(AsyncMysqlRowBlockIterator)
1059 ObjectData* AsyncMysqlRowBlockIterator::newInstance(Object row_block,
1060 size_t row_number) {
1061 ObjectData* ret = ObjectData::newInstance(getClass());
1062 auto* data = Native::data<AsyncMysqlRowBlockIterator>(ret);
1063 data->m_row_block = row_block;
1064 data->m_row_number = row_number;
1065 return ret;
1068 void HHVM_METHOD(AsyncMysqlRowBlockIterator, next) {
1069 auto* data = Native::data<AsyncMysqlRowBlockIterator>(this_);
1070 data->m_row_number++;
1073 bool HHVM_METHOD(AsyncMysqlRowBlockIterator, valid) {
1074 auto* data = Native::data<AsyncMysqlRowBlockIterator>(this_);
1076 static_assert(std::is_unsigned<typeof(data->m_row_number)>::value,
1077 "m_row_number should be unsigned");
1078 int64_t count = HHVM_MN(AsyncMysqlRowBlock, count)(
1079 data->m_row_block.get());
1080 return data->m_row_number < count;
1083 Object HHVM_METHOD(AsyncMysqlRowBlockIterator, current) {
1084 auto* data = Native::data<AsyncMysqlRowBlockIterator>(this_);
1086 if (!HHVM_MN(AsyncMysqlRowBlockIterator, valid)(this_)) {
1087 throw_iterator_not_valid();
1089 return HHVM_MN(AsyncMysqlRowBlock, getRow)(data->m_row_block.get(),
1090 data->m_row_number);
1093 int64_t HHVM_METHOD(AsyncMysqlRowBlockIterator, key) {
1094 auto* data = Native::data<AsyncMysqlRowBlockIterator>(this_);
1095 return data->m_row_number;
1098 void HHVM_METHOD(AsyncMysqlRowBlockIterator, rewind) {
1099 auto* data = Native::data<AsyncMysqlRowBlockIterator>(this_);
1100 data->m_row_number = 0;
1103 ///////////////////////////////////////////////////////////////////////////////
1104 // class AsyncMysqlRow
1106 Class* AsyncMysqlRow::s_class = nullptr;
1107 const StaticString AsyncMysqlRow::s_className("AsyncMysqlRow");
1109 IMPLEMENT_GET_CLASS(AsyncMysqlRow)
1111 ObjectData* AsyncMysqlRow::newInstance(Object row_block, size_t row_number) {
1112 ObjectData* ret = ObjectData::newInstance(getClass());
1113 auto* data = Native::data<AsyncMysqlRow>(ret);
1114 data->m_row_block = row_block;
1115 data->m_row_number = row_number;
1116 return ret;
1119 #define ROW_BLOCK(method, ...) HHVM_MN(AsyncMysqlRowBlock, method)( \
1120 data->m_row_block.get(), __VA_ARGS__) \
1122 Variant HHVM_METHOD(AsyncMysqlRow, at,
1123 const Variant& field) {
1124 auto* data = Native::data<AsyncMysqlRow>(this_);
1125 return ROW_BLOCK(at, data->m_row_number, field);
1128 int64_t HHVM_METHOD(AsyncMysqlRow, getFieldAsInt,
1129 const Variant& field) {
1130 auto* data = Native::data<AsyncMysqlRow>(this_);
1131 return ROW_BLOCK(getFieldAsInt, data->m_row_number, field);
1134 double HHVM_METHOD(AsyncMysqlRow, getFieldAsDouble,
1135 const Variant& field) {
1136 auto* data = Native::data<AsyncMysqlRow>(this_);
1137 return ROW_BLOCK(getFieldAsDouble, data->m_row_number, field);
1140 String HHVM_METHOD(AsyncMysqlRow, getFieldAsString,
1141 const Variant& field) {
1142 auto* data = Native::data<AsyncMysqlRow>(this_);
1143 return ROW_BLOCK(getFieldAsString, data->m_row_number, field);
1146 bool HHVM_METHOD(AsyncMysqlRow, isNull,
1147 const Variant& field) {
1148 auto* data = Native::data<AsyncMysqlRow>(this_);
1149 return ROW_BLOCK(isNull, data->m_row_number, field);
1152 int64_t HHVM_METHOD(AsyncMysqlRow, fieldType,
1153 const Variant& field) {
1154 auto* data = Native::data<AsyncMysqlRow>(this_);
1155 return ROW_BLOCK(fieldType, field);
1158 int64_t HHVM_METHOD(AsyncMysqlRow, count) {
1159 auto* data = Native::data<AsyncMysqlRow>(this_);
1160 return HHVM_MN(AsyncMysqlRowBlock, fieldsCount)(data->m_row_block.get());
1163 Object HHVM_METHOD(AsyncMysqlRow, getIterator) {
1164 ObjectData* it = AsyncMysqlRowIterator::newInstance(this_, 0);
1165 return Object(it);
1168 #undef ROW_BLOCK
1170 ///////////////////////////////////////////////////////////////////////////////
1171 // class AsyncMysqlRowIterator
1173 Class* AsyncMysqlRowIterator::s_class = nullptr;
1174 const StaticString AsyncMysqlRowIterator::s_className("AsyncMysqlRowIterator");
1176 IMPLEMENT_GET_CLASS(AsyncMysqlRowIterator)
1178 ObjectData* AsyncMysqlRowIterator::newInstance(Object row,
1179 size_t field_number) {
1180 ObjectData* ret = ObjectData::newInstance(getClass());
1181 auto* data = Native::data<AsyncMysqlRowIterator>(ret);
1182 data->m_row = row;
1183 data->m_field_number = field_number;
1184 return ret;
1187 void HHVM_METHOD(AsyncMysqlRowIterator, next) {
1188 auto* data = Native::data<AsyncMysqlRowIterator>(this_);
1189 data->m_field_number++;
1192 bool HHVM_METHOD(AsyncMysqlRowIterator, valid) {
1193 auto* data = Native::data<AsyncMysqlRowIterator>(this_);
1195 static_assert(std::is_unsigned<typeof(data->m_field_number)>::value,
1196 "m_field_number should be unsigned");
1197 int64_t count = HHVM_MN(AsyncMysqlRow, count)(data->m_row.get());
1198 return data->m_field_number < count;
1201 /*?? return as string? */
1202 String HHVM_METHOD(AsyncMysqlRowIterator, current) {
1203 auto* data = Native::data<AsyncMysqlRowIterator>(this_);
1204 return HHVM_MN(AsyncMysqlRow, getFieldAsString)(data->m_row.get(),
1205 data->m_field_number);
1208 int64_t HHVM_METHOD(AsyncMysqlRowIterator, key) {
1209 auto* data = Native::data<AsyncMysqlRowIterator>(this_);
1210 return data->m_field_number;
1213 void HHVM_METHOD(AsyncMysqlRowIterator, rewind) {
1214 auto* data = Native::data<AsyncMysqlRowIterator>(this_);
1215 data->m_field_number = 0;
1218 ///////////////////////////////////////////////////////////////////////////////
1220 #define REGISTER_CONSTANT(name) \
1221 Native::registerConstant<KindOfInt64>(s_##name.get(), k_##name) \
1223 static const int64_t DISABLE_COPY_AND_SWEEP = Native::NDIFlags::NO_COPY |
1224 Native::NDIFlags::NO_SWEEP;
1226 static class AsyncMysqlExtension final : public Extension {
1227 public:
1228 AsyncMysqlExtension() : Extension("async_mysql") {}
1229 void moduleInit() override {
1230 REGISTER_CONSTANT(NOT_NULL_FLAG);
1231 REGISTER_CONSTANT(PRI_KEY_FLAG);
1232 REGISTER_CONSTANT(UNIQUE_KEY_FLAG);
1233 REGISTER_CONSTANT(MULTIPLE_KEY_FLAG);
1234 REGISTER_CONSTANT(UNSIGNED_FLAG);
1235 REGISTER_CONSTANT(ZEROFILL_FLAG);
1236 REGISTER_CONSTANT(BINARY_FLAG);
1237 REGISTER_CONSTANT(AUTO_INCREMENT_FLAG);
1238 REGISTER_CONSTANT(ENUM_FLAG);
1239 REGISTER_CONSTANT(SET_FLAG);
1240 REGISTER_CONSTANT(BLOB_FLAG);
1241 REGISTER_CONSTANT(TIMESTAMP_FLAG);
1242 REGISTER_CONSTANT(NUM_FLAG);
1243 REGISTER_CONSTANT(NO_DEFAULT_VALUE_FLAG);
1245 REGISTER_CONSTANT(MYSQL_TYPE_TINY);
1246 REGISTER_CONSTANT(MYSQL_TYPE_SHORT);
1247 REGISTER_CONSTANT(MYSQL_TYPE_LONG);
1248 REGISTER_CONSTANT(MYSQL_TYPE_INT24);
1249 REGISTER_CONSTANT(MYSQL_TYPE_LONGLONG);
1250 REGISTER_CONSTANT(MYSQL_TYPE_DECIMAL);
1251 REGISTER_CONSTANT(MYSQL_TYPE_NEWDECIMAL);
1252 REGISTER_CONSTANT(MYSQL_TYPE_FLOAT);
1253 REGISTER_CONSTANT(MYSQL_TYPE_DOUBLE);
1254 REGISTER_CONSTANT(MYSQL_TYPE_BIT);
1255 REGISTER_CONSTANT(MYSQL_TYPE_TIMESTAMP);
1256 REGISTER_CONSTANT(MYSQL_TYPE_DATE);
1257 REGISTER_CONSTANT(MYSQL_TYPE_TIME);
1258 REGISTER_CONSTANT(MYSQL_TYPE_DATETIME);
1259 REGISTER_CONSTANT(MYSQL_TYPE_YEAR);
1260 REGISTER_CONSTANT(MYSQL_TYPE_STRING);
1261 REGISTER_CONSTANT(MYSQL_TYPE_VAR_STRING);
1262 REGISTER_CONSTANT(MYSQL_TYPE_BLOB);
1263 REGISTER_CONSTANT(MYSQL_TYPE_SET);
1264 REGISTER_CONSTANT(MYSQL_TYPE_ENUM);
1265 REGISTER_CONSTANT(MYSQL_TYPE_GEOMETRY);
1266 REGISTER_CONSTANT(MYSQL_TYPE_NULL);
1268 HHVM_STATIC_ME(AsyncMysqlClient, setPoolsConnectionLimit);
1269 HHVM_STATIC_ME(AsyncMysqlClient, connect);
1270 HHVM_STATIC_ME(AsyncMysqlClient, adoptConnection);
1272 HHVM_ME(AsyncMysqlConnectionPool, __construct);
1273 HHVM_ME(AsyncMysqlConnectionPool, getPoolStats);
1274 HHVM_ME(AsyncMysqlConnectionPool, connect);
1275 Native::registerNativeDataInfo<AsyncMysqlConnectionPool>(
1276 AsyncMysqlConnectionPool::s_className.get(), DISABLE_COPY_AND_SWEEP);
1278 HHVM_ME(AsyncMysqlConnection, query);
1279 HHVM_ME(AsyncMysqlConnection, queryf);
1280 HHVM_ME(AsyncMysqlConnection, multiQuery);
1281 HHVM_ME(AsyncMysqlConnection, escapeString);
1282 HHVM_ME(AsyncMysqlConnection, close);
1283 HHVM_ME(AsyncMysqlConnection, releaseConnection);
1284 HHVM_ME(AsyncMysqlConnection, serverInfo);
1285 HHVM_ME(AsyncMysqlConnection, warningCount);
1286 HHVM_ME(AsyncMysqlConnection, host);
1287 HHVM_ME(AsyncMysqlConnection, port);
1288 HHVM_ME(AsyncMysqlConnection, setReusable);
1289 HHVM_ME(AsyncMysqlConnection, isReusable);
1290 Native::registerNativeDataInfo<AsyncMysqlConnection>(
1291 AsyncMysqlConnection::s_className.get(), Native::NDIFlags::NO_COPY);
1293 HHVM_ME(AsyncMysqlErrorResult, elapsedMicros);
1294 HHVM_ME(AsyncMysqlErrorResult, startTime);
1295 HHVM_ME(AsyncMysqlErrorResult, endTime);
1296 HHVM_ME(AsyncMysqlErrorResult, mysql_errno);
1297 HHVM_ME(AsyncMysqlErrorResult, mysql_error);
1298 HHVM_ME(AsyncMysqlErrorResult, failureType);
1299 Native::registerNativeDataInfo<AsyncMysqlErrorResult>(
1300 AsyncMysqlErrorResult::s_className.get(), Native::NDIFlags::NO_COPY);
1302 HHVM_ME(AsyncMysqlQueryErrorResult, numSuccessfulQueries);
1303 HHVM_ME(AsyncMysqlQueryErrorResult, getSuccessfulResults);
1304 Native::registerNativeDataInfo<AsyncMysqlQueryErrorResult>(
1305 AsyncMysqlQueryErrorResult::s_className.get(),
1306 Native::NDIFlags::NO_COPY);
1308 HHVM_ME(AsyncMysqlQueryResult, elapsedMicros);
1309 HHVM_ME(AsyncMysqlQueryResult, startTime);
1310 HHVM_ME(AsyncMysqlQueryResult, endTime);
1311 HHVM_ME(AsyncMysqlQueryResult, numRowsAffected);
1312 HHVM_ME(AsyncMysqlQueryResult, lastInsertId);
1313 HHVM_ME(AsyncMysqlQueryResult, numRows);
1314 HHVM_ME(AsyncMysqlQueryResult, mapRows);
1315 HHVM_ME(AsyncMysqlQueryResult, vectorRows);
1316 HHVM_ME(AsyncMysqlQueryResult, mapRowsTyped);
1317 HHVM_ME(AsyncMysqlQueryResult, vectorRowsTyped);
1318 HHVM_ME(AsyncMysqlQueryResult, rowBlocks);
1319 Native::registerNativeDataInfo<AsyncMysqlQueryResult>(
1320 AsyncMysqlQueryResult::s_className.get(), Native::NDIFlags::NO_COPY);
1322 HHVM_ME(AsyncMysqlRowBlock, at);
1323 HHVM_ME(AsyncMysqlRowBlock, getFieldAsInt);
1324 HHVM_ME(AsyncMysqlRowBlock, getFieldAsDouble);
1325 HHVM_ME(AsyncMysqlRowBlock, getFieldAsString);
1326 HHVM_ME(AsyncMysqlRowBlock, isNull);
1327 HHVM_ME(AsyncMysqlRowBlock, fieldType);
1328 HHVM_ME(AsyncMysqlRowBlock, fieldFlags);
1329 HHVM_ME(AsyncMysqlRowBlock, fieldName);
1330 HHVM_ME(AsyncMysqlRowBlock, isEmpty);
1331 HHVM_ME(AsyncMysqlRowBlock, fieldsCount);
1332 HHVM_ME(AsyncMysqlRowBlock, count);
1333 HHVM_ME(AsyncMysqlRowBlock, getIterator);
1334 HHVM_ME(AsyncMysqlRowBlock, getRow);
1335 Native::registerNativeDataInfo<AsyncMysqlRowBlock>(
1336 AsyncMysqlRowBlock::s_className.get(), Native::NDIFlags::NO_COPY);
1338 HHVM_ME(AsyncMysqlRowBlockIterator, valid);
1339 HHVM_ME(AsyncMysqlRowBlockIterator, next);
1340 HHVM_ME(AsyncMysqlRowBlockIterator, current);
1341 HHVM_ME(AsyncMysqlRowBlockIterator, key);
1342 HHVM_ME(AsyncMysqlRowBlockIterator, rewind);
1343 Native::registerNativeDataInfo<AsyncMysqlRowBlockIterator>(
1344 AsyncMysqlRowBlockIterator::s_className.get(),
1345 DISABLE_COPY_AND_SWEEP);
1347 HHVM_ME(AsyncMysqlRow, at);
1348 HHVM_ME(AsyncMysqlRow, getFieldAsInt);
1349 HHVM_ME(AsyncMysqlRow, getFieldAsDouble);
1350 HHVM_ME(AsyncMysqlRow, getFieldAsString);
1351 HHVM_ME(AsyncMysqlRow, isNull);
1352 HHVM_ME(AsyncMysqlRow, fieldType);
1353 HHVM_ME(AsyncMysqlRow, count);
1354 HHVM_ME(AsyncMysqlRow, getIterator);
1355 Native::registerNativeDataInfo<AsyncMysqlRow>(
1356 AsyncMysqlRow::s_className.get(), DISABLE_COPY_AND_SWEEP);
1358 HHVM_ME(AsyncMysqlRowIterator, valid);
1359 HHVM_ME(AsyncMysqlRowIterator, next);
1360 HHVM_ME(AsyncMysqlRowIterator, current);
1361 HHVM_ME(AsyncMysqlRowIterator, key);
1362 HHVM_ME(AsyncMysqlRowIterator, rewind);
1363 Native::registerNativeDataInfo<AsyncMysqlRowIterator>(
1364 AsyncMysqlRowIterator::s_className.get(), DISABLE_COPY_AND_SWEEP);
1366 loadSystemlib("mysqlrow");
1367 loadSystemlib("async_mysql_exceptions");
1368 loadSystemlib();
1370 } s_async_mysql_extension;
1372 ///////////////////////////////////////////////////////////////////////////////