Codemod asserts to assertxs in the runtime
[hiphop-php.git] / hphp / runtime / ext / async_mysql / ext_async_mysql.cpp
blobc697c462a727e1357964dd7618b72c0b1c4d905e
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>
24 #include <squangle/mysql_client/ClientPool.h>
26 #include "hphp/runtime/base/array-init.h"
27 #include "hphp/runtime/ext/collections/ext_collections-map.h"
28 #include "hphp/runtime/ext/collections/ext_collections-vector.h"
29 #include "hphp/runtime/ext/mysql/ext_mysql.h"
30 #include "hphp/runtime/ext/mysql/mysql_common.h"
31 #include "hphp/runtime/vm/native-data.h"
32 #include "hphp/system/systemlib.h"
33 #include "hphp/util/logger.h"
35 namespace HPHP {
36 ///////////////////////////////////////////////////////////////////////////////
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 typedef am::ClientPool<am::AsyncMysqlClient, am::AsyncMysqlClientFactory>
48 AsyncMysqlClientPool;
50 namespace {
51 int HdfAsyncMysqlClientPoolSize = -1;
53 folly::Singleton<AsyncMysqlClientPool> clientPool([]() {
54 if (HdfAsyncMysqlClientPoolSize == -1) {
55 LOG(DFATAL) << "AsyncMysql Config should have been initialized.";
56 HdfAsyncMysqlClientPoolSize = 2;
58 return new AsyncMysqlClientPool(
59 std::make_unique<am::AsyncMysqlClientFactory>(),
60 HdfAsyncMysqlClientPoolSize);
61 });
64 static std::shared_ptr<am::AsyncMysqlClient> getClient() {
65 return folly::Singleton<AsyncMysqlClientPool>::try_get()->getClient();
68 ///////////////////////////////////////////////////////////////////////////
69 // AsyncMysqlClientStats
71 struct AsyncMysqlClientStats {
72 AsyncMysqlClientStats& operator=(const AsyncMysqlClientStats& other) {
73 m_values = other.m_values;
74 return *this;
77 static Class* getClass();
78 static Object newInstance(db::ClientPerfStats values) {
79 Object obj{getClass()};
80 auto* data = Native::data<AsyncMysqlClientStats>(obj);
81 data->setPerfValues(std::move(values));
82 return obj;
85 void setPerfValues(db::ClientPerfStats values) {
86 m_values = std::move(values);
89 static Class* s_class;
90 static const StaticString s_className;
92 db::ClientPerfStats m_values;
95 Class* AsyncMysqlClientStats::s_class = nullptr;
96 const StaticString AsyncMysqlClientStats::s_className("AsyncMysqlClientStats");
98 IMPLEMENT_GET_CLASS(AsyncMysqlClientStats)
100 static double HHVM_METHOD(AsyncMysqlClientStats, ioEventLoopMicrosAvg) {
101 auto* data = Native::data<AsyncMysqlClientStats>(this_);
102 return data->m_values.ioEventLoopMicrosAvg;
105 static double HHVM_METHOD(AsyncMysqlClientStats, callbackDelayMicrosAvg) {
106 auto* data = Native::data<AsyncMysqlClientStats>(this_);
107 return data->m_values.callbackDelayMicrosAvg;
110 static double HHVM_METHOD(AsyncMysqlClientStats, ioThreadBusyMicrosAvg) {
111 auto* data = Native::data<AsyncMysqlClientStats>(this_);
112 return data->m_values.ioThreadBusyTime;
115 static double HHVM_METHOD(AsyncMysqlClientStats, ioThreadIdleMicrosAvg) {
116 auto* data = Native::data<AsyncMysqlClientStats>(this_);
117 return data->m_values.ioThreadIdleTime;
120 static int64_t HHVM_METHOD(AsyncMysqlClientStats, notificationQueueSize) {
121 auto* data = Native::data<AsyncMysqlClientStats>(this_);
122 return data->m_values.notificationQueueSize;
125 //////////////////////////////////////////////////////////////////////////////
126 // MySSLContextProvider
127 MySSLContextProvider::MySSLContextProvider(
128 std::shared_ptr<am::SSLOptionsProviderBase> provider)
129 : m_provider(provider) {}
131 Object MySSLContextProvider::newInstance(
132 std::shared_ptr<am::SSLOptionsProviderBase> ssl_provider) {
133 Object obj{getClass()};
134 Native::data<MySSLContextProvider>(obj)->setSSLProvider(
135 std::move(ssl_provider));
136 return obj;
139 std::shared_ptr<am::SSLOptionsProviderBase>
140 MySSLContextProvider::getSSLProvider() {
141 return m_provider;
143 void MySSLContextProvider::setSSLProvider(
144 std::shared_ptr<am::SSLOptionsProviderBase> ssl_provider) {
145 m_provider = std::move(ssl_provider);
148 static bool HHVM_METHOD(MySSLContextProvider, isValid) {
149 auto* data = Native::data<MySSLContextProvider>(this_);
150 return data->m_provider != nullptr;
153 Class* MySSLContextProvider::s_class = nullptr;
154 const StaticString MySSLContextProvider::s_className("MySSLContextProvider");
155 IMPLEMENT_GET_CLASS(MySSLContextProvider)
157 //////////////////////////////////////////////////////////////////////////////
158 // AsyncMysqlConnectionOptions
160 AsyncMysqlConnectionOptions::AsyncMysqlConnectionOptions() {
161 // set default timeout
162 auto default_timeout = mysqlExtension::ConnectTimeout * 1000;
163 m_conn_opts.setTotalTimeout(am::Duration(default_timeout));
166 const am::ConnectionOptions&
167 AsyncMysqlConnectionOptions::getConnectionOptions() {
168 return m_conn_opts;
171 static void
172 HHVM_METHOD(AsyncMysqlConnectionOptions, setConnectTimeout, int64_t timeout) {
173 auto* data = Native::data<AsyncMysqlConnectionOptions>(this_);
174 data->m_conn_opts.setTimeout(am::Duration(timeout));
177 static void
178 HHVM_METHOD(AsyncMysqlConnectionOptions, setConnectAttempts, int32_t attempts) {
179 auto* data = Native::data<AsyncMysqlConnectionOptions>(this_);
180 data->m_conn_opts.setConnectAttempts(attempts);
183 static void
184 HHVM_METHOD(AsyncMysqlConnectionOptions, setTotalTimeout, int64_t timeout) {
185 auto* data = Native::data<AsyncMysqlConnectionOptions>(this_);
186 data->m_conn_opts.setTotalTimeout(am::Duration(timeout));
189 static void
190 HHVM_METHOD(AsyncMysqlConnectionOptions, setQueryTimeout, int64_t timeout) {
191 auto* data = Native::data<AsyncMysqlConnectionOptions>(this_);
192 data->m_conn_opts.setQueryTimeout(am::Duration(timeout));
195 static void HHVM_METHOD(
196 AsyncMysqlConnectionOptions,
197 setConnectionAttributes,
198 const Array& attrs) {
199 auto* data = Native::data<AsyncMysqlConnectionOptions>(this_);
201 IterateKV(attrs.get(), [&](Cell k, TypedValue v) {
202 data->m_conn_opts.setConnectionAttribute(
203 tvCastToString(k).toCppString(),
204 tvCastToString(v).toCppString()
209 static void HHVM_METHOD(
210 AsyncMysqlConnectionOptions,
211 setSSLOptionsProvider,
212 const Variant& sslContextProvider /* = null */) {
213 if (sslContextProvider.isNull()) {
214 return;
216 if (!sslContextProvider.isObject() ||
217 !sslContextProvider.toObject()->instanceof
218 (MySSLContextProvider::getClass())) {
219 SystemLib::throwInvalidArgumentExceptionObject(
220 "Wrong type: expected MySSLContextProvider argument");
221 return;
223 auto* sslProvider =
224 Native::data<MySSLContextProvider>(sslContextProvider.toObject());
225 auto* data = Native::data<AsyncMysqlConnectionOptions>(this_);
226 data->m_conn_opts.setSSLOptionsProvider(sslProvider->getSSLProvider());
229 static int64_t getQueryTimeout(int64_t timeout_micros) {
230 if (timeout_micros < 0) {
231 return mysqlExtension::ReadTimeout * 1000;
232 } else {
233 return timeout_micros;
237 static std::vector<am::Query> transformQueries(const Array& queries) {
238 std::vector<am::Query> queries_vec;
239 queries_vec.reserve(queries.size());
240 for (ArrayIter iter(queries); iter; ++iter) {
241 queries_vec.emplace_back(am::Query::unsafe(
242 static_cast<std::string>(iter.second().toString().data())));
244 return queries_vec;
247 Class* AsyncMysqlConnectionOptions::s_class = nullptr;
248 const StaticString AsyncMysqlConnectionOptions::s_className(
249 "AsyncMysqlConnectionOptions");
250 IMPLEMENT_GET_CLASS(AsyncMysqlConnectionOptions)
252 //////////////////////////////////////////////////////////////////////////////
253 // AsyncMysqlClient
254 void HHVM_STATIC_METHOD(
255 AsyncMysqlClient,
256 setPoolsConnectionLimit,
257 int64_t limit) {
258 getClient()->setPoolsConnectionLimit(limit);
261 static Object newAsyncMysqlConnectEvent(
262 std::shared_ptr<am::ConnectOperation> op,
263 std::shared_ptr<am::AsyncMysqlClient> clientPtr) {
264 auto event = new AsyncMysqlConnectEvent(op);
265 try {
266 op->setCallback([event, clientPtr](am::ConnectOperation& /*op*/) {
267 // Get current stats
268 event->setClientStats(clientPtr->collectPerfStats());
270 event->opFinished();
272 op->run();
274 return Object{event->getWaitHandle()};
275 } catch (...) {
276 assertx(false);
277 event->abandon();
278 return Object{};
282 Object HHVM_STATIC_METHOD(
283 AsyncMysqlClient,
284 connect,
285 const String& host,
286 int port,
287 const String& dbname,
288 const String& user,
289 const String& password,
290 int64_t timeout_micros /* = -1 */,
291 const Variant& sslContextProvider /* = null */) {
292 am::ConnectionKey key(
293 static_cast<std::string>(host),
294 port,
295 static_cast<std::string>(dbname),
296 static_cast<std::string>(user),
297 static_cast<std::string>(password));
298 auto op = getClient()->beginConnection(key);
299 if (!sslContextProvider.isNull()) {
300 auto* mysslContextProvider =
301 Native::data<MySSLContextProvider>(sslContextProvider.toObject());
302 op->setSSLOptionsProvider(mysslContextProvider->getSSLProvider());
305 if (timeout_micros < 0) {
306 timeout_micros = mysqlExtension::ConnectTimeout * 1000;
308 if (timeout_micros > 0) {
309 op->setTimeout(am::Duration(timeout_micros));
312 return newAsyncMysqlConnectEvent(std::move(op), getClient());
315 Object HHVM_STATIC_METHOD(
316 AsyncMysqlClient,
317 connectWithOpts,
318 const String& host,
319 int port,
320 const String& dbname,
321 const String& user,
322 const String& password,
323 const Object& asyncMysqlConnOpts) {
324 am::ConnectionKey key(
325 static_cast<std::string>(host),
326 port,
327 static_cast<std::string>(dbname),
328 static_cast<std::string>(user),
329 static_cast<std::string>(password));
330 auto op = getClient()->beginConnection(key);
332 auto* obj = Native::data<AsyncMysqlConnectionOptions>(asyncMysqlConnOpts);
333 const auto& connOpts = obj->getConnectionOptions();
334 op->setConnectionOptions(connOpts);
336 return newAsyncMysqlConnectEvent(std::move(op), getClient());
339 Object HHVM_STATIC_METHOD(
340 AsyncMysqlClient,
341 connectAndQuery,
342 const Array& queries,
343 const String& host,
344 int port,
345 const String& dbname,
346 const String& user,
347 const String& password,
348 const Object& asyncMysqlConnOpts) {
349 am::ConnectionKey key(
350 static_cast<std::string>(host),
351 port,
352 static_cast<std::string>(dbname),
353 static_cast<std::string>(user),
354 static_cast<std::string>(password));
355 auto clientPtr = getClient();
356 auto connectOp = clientPtr->beginConnection(key);
357 auto* obj = Native::data<AsyncMysqlConnectionOptions>(asyncMysqlConnOpts);
358 const auto& connOpts = obj->getConnectionOptions();
359 connectOp->setConnectionOptions(connOpts);
360 auto event = new AsyncMysqlMultiQueryEvent();
361 try {
362 connectOp->setCallback([clientPtr, event, queries]
363 (am::ConnectOperation& op) {
365 auto query_op = am::Connection::beginMultiQuery(
366 op.releaseConnection(), transformQueries(queries));
367 event->setQueryOp(query_op);
369 try {
370 am::MultiQueryAppenderCallback appender_callback = [event, clientPtr](
371 am::MultiQueryOperation& op,
372 std::vector<am::QueryResult> query_results,
373 am::QueryCallbackReason reason) {
374 DCHECK(reason != am::QueryCallbackReason::RowsFetched);
375 DCHECK(reason != am::QueryCallbackReason::QueryBoundary);
376 if (!op.done()) {
377 LOG(ERROR) << "Invalid state! Callback called as finished "
378 << "but operation didn't finish";
380 op.setQueryResults(std::move(query_results));
381 event->setClientStats(clientPtr->collectPerfStats());
382 event->opFinished();
384 query_op->setCallback(am::resultAppender(appender_callback));
385 query_op->run();
386 } catch (...) {
387 LOG(ERROR) << "Unexpected exception while executing Query";
388 event->abandon();
392 connectOp->run();
393 return Object{event->getWaitHandle()};
394 } catch (...) {
395 LOG(ERROR) << "Unexpected exception while creating Connection";
396 event->abandon();
397 return Object{};
401 Object HHVM_STATIC_METHOD(
402 AsyncMysqlClient,
403 adoptConnection,
404 const Variant& connection) {
405 auto conn = cast<MySQLResource>(connection)->mysql();
406 // mysql connection from ext/mysql/mysql_common.h
407 auto raw_conn = conn->eject_mysql();
408 auto adopted = getClient()->adoptConnection(
409 raw_conn,
410 conn->m_host,
411 conn->m_port,
412 conn->m_database,
413 conn->m_username,
414 conn->m_password);
415 return AsyncMysqlConnection::newInstance(std::move(adopted));
418 ///////////////////////////////////////////////////////////////////////////////
419 // class AsyncMysqlConnectionPool
421 const StaticString AsyncMysqlConnectionPool::s_className(
422 "AsyncMysqlConnectionPool");
424 // `connection_limit` - Defines the limit of opened connections for each set of
425 // User, Database, Host, etc
426 // `total_connection_limit` - Defines the total limit of opened connection as a
427 // whole
428 // `idle_timeout_micros` - Sets the maximum idle time in microseconds a
429 // connection can be left in the pool without being killed by the pool
430 // `age_timeout_micros` - Sets the maximum age (means the time since started) of
431 // a connection, the pool will then kill this connection when reaches that limit
432 // `expiration_policy` - We offer 2 policies for the expiration of a
433 // connection: `IdleTime` and `Age`, in the Idle policy a connection will only
434 // die after some time being idle; in Age policy we extend the idle one to kill
435 // also by age
437 const StaticString s_per_key_connection_limit("per_key_connection_limit"),
438 s_pool_connection_limit("pool_connection_limit"),
439 s_idle_timeout_micros("idle_timeout_micros"),
440 s_age_timeout_micros("age_timeout_micros"),
441 s_expiration_policy("expiration_policy");
443 static void
444 HHVM_METHOD(AsyncMysqlConnectionPool, __construct, const Array& options) {
445 auto* data = Native::data<AsyncMysqlConnectionPool>(this_);
446 am::PoolOptions pool_options;
447 if (options.exists(s_per_key_connection_limit)) {
448 pool_options.setPerKeyLimit(options[s_per_key_connection_limit].toInt32());
450 if (options.exists(s_pool_connection_limit)) {
451 pool_options.setPoolLimit(options[s_pool_connection_limit].toInt32());
453 if (options.exists(s_idle_timeout_micros)) {
454 pool_options.setIdleTimeout(
455 am::Duration(options[s_idle_timeout_micros].toInt64()));
457 if (options.exists(s_age_timeout_micros)) {
458 pool_options.setAgeTimeout(
459 am::Duration(options[s_age_timeout_micros].toInt64()));
461 if (options.exists(s_expiration_policy)) {
462 pool_options.setExpPolicy(options[s_expiration_policy].toString() ==
463 String::FromCStr("IdleTime")
464 ? am::ExpirationPolicy::IdleTime
465 : am::ExpirationPolicy::Age);
467 data->m_async_pool =
468 am::AsyncConnectionPool::makePool(getClient(), pool_options);
471 void AsyncMysqlConnectionPool::sweep() {
472 if (m_async_pool) {
473 m_async_pool->shutdown();
474 m_async_pool.reset();
478 // `created_pool_connections` - Number of connections created by the pool
479 // `destroyed_pool_connections` - Number of connections destroyed by the pool,
480 // be careful with this number, it will only be equal to the above when all
481 // created connections have been close. This may not be true by the end of
482 // a request.
483 // `connections_requested` - This number helps with comparing how many
484 // connection would have been made if the there were no pooling.
485 // `pool_hits` - Counts the number of times a request for connection went to
486 // the pool and it had a connection ready in cache
487 // `pool_misses` - Counts the number of times a we needed a connection and
488 // none was ready to return
489 const StaticString s_created_pool_connections("created_pool_connections"),
490 s_destroyed_pool_connections("destroyed_pool_connections"),
491 s_connections_requested("connections_requested"), s_pool_hits("pool_hits"),
492 s_pool_misses("pool_misses");
494 static Array HHVM_METHOD(AsyncMysqlConnectionPool, getPoolStats) {
495 auto* data = Native::data<AsyncMysqlConnectionPool>(this_);
496 auto* pool_stats = data->m_async_pool->stats();
497 Array ret = make_map_array(
498 s_created_pool_connections,
499 pool_stats->numCreatedPoolConnections(),
500 s_destroyed_pool_connections,
501 pool_stats->numDestroyedPoolConnections(),
502 s_connections_requested,
503 pool_stats->numConnectionsRequested(),
504 s_pool_hits,
505 pool_stats->numPoolHits(),
506 s_pool_misses,
507 pool_stats->numPoolMisses());
508 return ret;
511 static Object HHVM_METHOD(
512 AsyncMysqlConnectionPool,
513 connect,
514 const String& host,
515 int port,
516 const String& dbname,
517 const String& user,
518 const String& password,
519 int64_t timeout_micros,
520 const String& extra_key) {
521 auto* data = Native::data<AsyncMysqlConnectionPool>(this_);
522 auto op = data->m_async_pool->beginConnection(
523 static_cast<std::string>(host),
524 port,
525 static_cast<std::string>(dbname),
526 static_cast<std::string>(user),
527 static_cast<std::string>(password),
528 static_cast<std::string>(extra_key));
529 if (timeout_micros < 0) {
530 timeout_micros = mysqlExtension::ConnectTimeout * 1000;
532 if (timeout_micros > 0) {
533 op->setTimeout(am::Duration(timeout_micros));
536 return newAsyncMysqlConnectEvent(
537 std::move(op), data->m_async_pool->getMysqlClient());
540 static Object HHVM_METHOD(
541 AsyncMysqlConnectionPool,
542 connectWithOpts,
543 const String& host,
544 int port,
545 const String& dbname,
546 const String& user,
547 const String& password,
548 const Object& asyncMysqlConnOpts,
549 const String& extra_key) {
550 auto* data = Native::data<AsyncMysqlConnectionPool>(this_);
551 auto op = data->m_async_pool->beginConnection(
552 static_cast<std::string>(host),
553 port,
554 static_cast<std::string>(dbname),
555 static_cast<std::string>(user),
556 static_cast<std::string>(password),
557 static_cast<std::string>(extra_key));
559 auto* obj = Native::data<AsyncMysqlConnectionOptions>(asyncMysqlConnOpts);
560 const auto& connOpts = obj->getConnectionOptions();
561 op->setConnectionOptions(connOpts);
563 return newAsyncMysqlConnectEvent(
564 std::move(op), data->m_async_pool->getMysqlClient());
567 ///////////////////////////////////////////////////////////////////////////////
568 // class AsyncMysqlConnection
570 Class* AsyncMysqlConnection::s_class = nullptr;
571 const StaticString AsyncMysqlConnection::s_className("AsyncMysqlConnection");
573 IMPLEMENT_GET_CLASS(AsyncMysqlConnection)
575 Object AsyncMysqlConnection::newInstance(
576 std::unique_ptr<am::Connection> conn,
577 std::shared_ptr<am::ConnectOperation> conn_op,
578 db::ClientPerfStats clientStats) {
579 Object ret{getClass()};
580 auto* retPtr = Native::data<AsyncMysqlConnection>(ret);
581 retPtr->setConnection(std::move(conn));
582 retPtr->setConnectOperation(std::move(conn_op));
583 retPtr->setClientStats(std::move(clientStats));
584 return ret;
587 AsyncMysqlConnection::AsyncMysqlConnection() : m_port(0), m_closed(false) {}
589 void AsyncMysqlConnection::sweep() {
590 m_conn.reset();
593 void AsyncMysqlConnection::setConnection(std::unique_ptr<am::Connection> conn) {
594 m_conn = std::move(conn);
595 m_host = String(m_conn->host(), CopyString);
596 m_port = m_conn->port();
599 void AsyncMysqlConnection::setConnectOperation(
600 std::shared_ptr<am::ConnectOperation> op) {
601 m_op = std::move(op);
604 void AsyncMysqlConnection::setClientStats(db::ClientPerfStats clientStats) {
605 m_clientStats = std::move(clientStats);
608 void AsyncMysqlConnection::verifyValidConnection() {
609 if (UNLIKELY(!m_conn || !m_conn->ok())) {
610 if (m_closed) {
611 SystemLib::throwInvalidArgumentExceptionObject(
612 "attempt to invoke method on a closed connection");
613 } else if (m_conn && !m_conn->ok()) {
614 SystemLib::throwInvalidArgumentExceptionObject(
615 "attempt to invoke method on an invalid connection");
616 } else {
617 SystemLib::throwInvalidArgumentExceptionObject(
618 "attempt to invoke method on a busy connection");
623 bool AsyncMysqlConnection::isValidConnection() {
624 // When a query timeout happens, the connection is invalid and SQuangLe
625 // layer closes it for precaution.
626 return m_conn && m_conn->ok() && !m_closed;
629 Object AsyncMysqlConnection::query(
630 ObjectData* this_,
631 am::Query query,
632 int64_t timeout_micros /* = -1 */) {
634 verifyValidConnection();
635 auto* clientPtr = static_cast<am::AsyncMysqlClient*>(m_conn->client());
636 auto op = am::Connection::beginQuery(std::move(m_conn), query);
637 op->setTimeout(am::Duration(getQueryTimeout(timeout_micros)));
639 auto event = new AsyncMysqlQueryEvent(this_, op);
640 try {
641 am::QueryAppenderCallback appender_callback = [event, clientPtr](
642 am::QueryOperation& op,
643 am::QueryResult query_result,
644 am::QueryCallbackReason reason) {
645 DCHECK(reason != am::QueryCallbackReason::RowsFetched);
646 if (!op.done()) {
647 LOG(ERROR) << "Invalid state! Callback called as finished "
648 << "but operation didn't finish";
651 op.setQueryResult(std::move(query_result));
652 event->setClientStats(clientPtr->collectPerfStats());
653 event->opFinished();
655 op->setCallback(am::resultAppender(appender_callback));
656 op->run();
658 return Object{event->getWaitHandle()};
660 catch (...) {
661 LOG(ERROR) << "Unexpected exception while beginning ConnectOperation";
662 assertx(false);
663 event->abandon();
664 return Object{};
668 static Object HHVM_METHOD(
669 AsyncMysqlConnection,
670 query,
671 const String& query,
672 int64_t timeout_micros /* = -1 */) {
673 auto* data = Native::data<AsyncMysqlConnection>(this_);
675 return data->query(
676 this_,
677 am::Query::unsafe(static_cast<std::string>(query)),
678 timeout_micros);
681 static Object HHVM_METHOD(
682 AsyncMysqlConnection,
683 queryf,
684 const String& pattern,
685 const Array& args) {
686 auto* data = Native::data<AsyncMysqlConnection>(this_);
688 // Not directly calling argsv.toFollyDynamic() as that creates a folly
689 // dynamic object, not list
690 std::vector<am::QueryArgument> query_args;
691 query_args.reserve(args.length());
693 auto scalarPush = [](
694 std::vector<am::QueryArgument>& list, const Variant& arg
696 if (arg.isInteger()) {
697 list.push_back(arg.toInt64());
698 } else if (arg.isDouble()) {
699 list.push_back(arg.toDouble());
700 } else if (arg.isString()) {
701 list.push_back(static_cast<std::string>(arg.toString()));
702 } else if (arg.isNull()) {
703 list.push_back(nullptr);
704 } else {
705 return false;
707 return true;
710 for (ArrayIter iter(args); iter; ++iter) {
711 const Variant& arg = iter.second();
712 if (scalarPush(query_args, arg)) {
713 continue;
716 if (arg.isObject()) {
717 const Object& obj = arg.asCObjRef();
718 if (obj->isCollection() && isVectorCollection(obj->collectionType())) {
719 std::vector<am::QueryArgument> out;
720 out.reserve(collections::getSize(obj.get()));
721 for (ArrayIter listIter(arg); listIter; ++listIter) {
722 const Variant& item = listIter.second();
723 if (scalarPush(out, item)) {
724 continue;
726 throw_invalid_argument(
727 "queryf arguments must be scalars, or Vectors of scalars. "
728 "Parameter %ld is a Vector containing a %s at index %ld",
729 query_args.size(),
730 getDataTypeString(item.getType()).c_str(),
731 out.size()
734 query_args.push_back(out);
735 continue;
739 throw_invalid_argument(
740 "queryf parameters must be scalars, or Vectors of scalars. "
741 "Parameter %ld is a %s",
742 query_args.size(),
743 getDataTypeString(arg.getType()).c_str()
747 return data->query(
748 this_, am::Query(static_cast<std::string>(pattern), query_args));
751 static Object HHVM_METHOD(
752 AsyncMysqlConnection,
753 multiQuery,
754 const Array& queries,
755 int64_t timeout_micros /* = -1 */) {
756 auto* data = Native::data<AsyncMysqlConnection>(this_);
757 data->verifyValidConnection();
758 auto* clientPtr = static_cast<am::AsyncMysqlClient*>(data->m_conn->client());
759 auto op = am::Connection::beginMultiQuery(std::move(data->m_conn),
760 transformQueries(queries));
761 op->setTimeout(am::Duration(getQueryTimeout(timeout_micros)));
763 auto event = new AsyncMysqlMultiQueryEvent(this_, op);
764 try {
765 am::MultiQueryAppenderCallback appender_callback = [event, clientPtr](
766 am::MultiQueryOperation& op,
767 std::vector<am::QueryResult> query_results,
768 am::QueryCallbackReason reason) {
769 DCHECK(reason != am::QueryCallbackReason::RowsFetched);
770 DCHECK(reason != am::QueryCallbackReason::QueryBoundary);
771 if (!op.done()) {
772 LOG(ERROR) << "Invalid state! Callback called as finished "
773 << "but operation didn't finish";
776 op.setQueryResults(std::move(query_results));
777 event->setClientStats(clientPtr->collectPerfStats());
778 event->opFinished();
780 op->setCallback(am::resultAppender(appender_callback));
781 op->run();
783 return Object{event->getWaitHandle()};
785 catch (...) {
786 assertx(false);
787 event->abandon();
788 return Object{};
792 static bool HHVM_METHOD(AsyncMysqlConnection, isValid) {
793 auto* data = Native::data<AsyncMysqlConnection>(this_);
794 return data->isValidConnection();
797 static String
798 HHVM_METHOD(AsyncMysqlConnection, escapeString, const String& input) {
799 auto* data = Native::data<AsyncMysqlConnection>(this_);
801 data->verifyValidConnection();
802 String ret = data->m_conn->escapeString(input.data());
803 return ret;
806 static String HHVM_METHOD(AsyncMysqlConnection, serverInfo) {
807 auto* data = Native::data<AsyncMysqlConnection>(this_);
809 String ret = "";
810 if (data->isValidConnection()) {
811 ret = data->m_conn->serverInfo();
812 } else {
813 LOG(ERROR) << "Accessing closed connection";
815 return ret;
818 static bool HHVM_METHOD(AsyncMysqlConnection, sslSessionReused) {
819 auto* data = Native::data<AsyncMysqlConnection>(this_);
821 // Will throw PHP catchable Exception in case the connection isn't valid.
822 data->verifyValidConnection();
823 return data->m_conn->sslSessionReused();
826 static bool HHVM_METHOD(AsyncMysqlConnection, isSSL) {
827 auto* data = Native::data<AsyncMysqlConnection>(this_);
829 // Will throw PHP catchable Exception in case the connection isn't valid.
830 data->verifyValidConnection();
831 return data->m_conn->isSSL();
834 static int HHVM_METHOD(AsyncMysqlConnection, warningCount) {
835 auto* data = Native::data<AsyncMysqlConnection>(this_);
837 int count = 0;
838 if (data->isValidConnection()) {
839 count = data->m_conn->warningCount();
840 } else {
841 LOG(ERROR) << "Accessing closed connection";
843 return count;
846 static String HHVM_METHOD(AsyncMysqlConnection, host) {
847 auto* data = Native::data<AsyncMysqlConnection>(this_);
848 return data->m_host;
851 static int HHVM_METHOD(AsyncMysqlConnection, port) {
852 auto* data = Native::data<AsyncMysqlConnection>(this_);
853 return data->m_port;
856 static void HHVM_METHOD(AsyncMysqlConnection, setReusable, bool reusable) {
857 auto* data = Native::data<AsyncMysqlConnection>(this_);
859 if (data->m_conn) {
860 data->m_conn->setReusable(reusable);
861 } else {
862 LOG(ERROR) << "Accessing closed connection";
866 static bool HHVM_METHOD(AsyncMysqlConnection, isReusable) {
867 auto* data = Native::data<AsyncMysqlConnection>(this_);
869 if (data->m_conn) {
870 return data->m_conn->isReusable();
871 } else {
872 LOG(ERROR) << "Accessing closed connection";
874 return false;
877 static Variant HHVM_METHOD(AsyncMysqlConnection, connectResult) {
878 auto* data = Native::data<AsyncMysqlConnection>(this_);
880 if (data->m_op) {
881 return AsyncMysqlConnectResult::newInstance(data->m_op,
882 data->m_clientStats);
883 } else {
884 LOG(ERROR) << "ConnectResult only available when Connection created by "
885 "AsyncMysqlClient";
887 return false;
890 static double HHVM_METHOD(AsyncMysqlConnection, lastActivityTime) {
891 auto* data = Native::data<AsyncMysqlConnection>(this_);
893 if (data->m_conn) {
894 auto d = std::chrono::duration_cast<std::chrono::microseconds>(
895 data->m_op->startTime().time_since_epoch());
896 return d.count() / 1000.0 / 1000.0;
897 } else {
898 LOG(ERROR) << "Accessing closed connection";
900 return false;
903 static void HHVM_METHOD(AsyncMysqlConnection, close) {
904 auto* data = Native::data<AsyncMysqlConnection>(this_);
906 data->m_conn.reset();
907 data->m_closed = true;
910 static Variant HHVM_METHOD(AsyncMysqlConnection, releaseConnection) {
911 auto* data = Native::data<AsyncMysqlConnection>(this_);
912 data->verifyValidConnection();
914 auto raw_connection = data->m_conn->stealMysql();
915 auto host = data->m_conn->host();
916 auto port = data->m_conn->port();
917 auto username = data->m_conn->user();
918 auto database = data->m_conn->database();
919 data->m_conn.reset();
920 data->m_closed = true;
921 return Variant(
922 req::make<MySQLResource>(
923 std::make_shared<MySQL>(host.c_str(),
924 port,
925 username.c_str(),
927 database.c_str(),
928 raw_connection)));
931 ///////////////////////////////////////////////////////////////////////////////
932 // class AsyncMysqlResult
934 int64_t AsyncMysqlResult::elapsedMicros() {
935 return op()->elapsed().count();
938 double AsyncMysqlResult::startTime() {
939 am::Duration d = std::chrono::duration_cast<std::chrono::microseconds>(
940 op()->startTime().time_since_epoch());
941 return d.count() / 1000.0 / 1000.0;
944 double AsyncMysqlResult::endTime() {
945 am::Duration d = std::chrono::duration_cast<std::chrono::microseconds>(
946 op()->endTime().time_since_epoch());
947 return d.count() / 1000.0 / 1000.0;
950 am::Operation* AsyncMysqlResult::op() {
951 if (m_op.get() == nullptr) {
952 // m_op is null if this object is directly created. It is possible if
953 // a derived class is defined that does not call this class' constructor.
954 SystemLib::throwInvalidOperationExceptionObject(
955 "AsyncMysqlErrorResult object is not properly initialized.");
957 return m_op.get();
960 Object AsyncMysqlResult::clientStats() {
961 return AsyncMysqlClientStats::newInstance(m_clientStats);
964 #define DEFINE_PROXY_METHOD(cls, method, type) \
965 type HHVM_METHOD(cls, method) { return Native::data<cls>(this_)->method(); }
967 #define EXTENDS_ASYNC_MYSQL_RESULT(cls) \
968 DEFINE_PROXY_METHOD(cls, elapsedMicros, int64_t) \
969 DEFINE_PROXY_METHOD(cls, startTime, double) \
970 DEFINE_PROXY_METHOD(cls, endTime, double) \
971 DEFINE_PROXY_METHOD(cls, clientStats, Object)
973 ///////////////////////////////////////////////////////////////////////////////
974 // class AsyncMysqlConnectResult
976 Class* AsyncMysqlConnectResult::s_class = nullptr;
977 const StaticString AsyncMysqlConnectResult::s_className(
978 "AsyncMysqlConnectResult");
980 IMPLEMENT_GET_CLASS(AsyncMysqlConnectResult)
982 Object AsyncMysqlConnectResult::newInstance(std::shared_ptr<am::Operation> op,
983 db::ClientPerfStats values) {
984 Object ret{getClass()};
985 Native::data<AsyncMysqlConnectResult>(ret)
986 ->create(std::move(op), std::move(values));
987 return ret;
990 EXTENDS_ASYNC_MYSQL_RESULT(AsyncMysqlConnectResult)
992 ///////////////////////////////////////////////////////////////////////////////
993 // class AsyncMysqlErrorResult
995 Class* AsyncMysqlErrorResult::s_class = nullptr;
996 const StaticString AsyncMysqlErrorResult::s_className("AsyncMysqlErrorResult");
998 IMPLEMENT_GET_CLASS(AsyncMysqlErrorResult)
1000 Object AsyncMysqlErrorResult::newInstance(std::shared_ptr<am::Operation> op,
1001 db::ClientPerfStats values) {
1002 Object ret{getClass()};
1003 Native::data<AsyncMysqlErrorResult>(ret)
1004 ->create(std::move(op), std::move(values));
1005 return ret;
1008 EXTENDS_ASYNC_MYSQL_RESULT(AsyncMysqlErrorResult)
1010 static int HHVM_METHOD(AsyncMysqlErrorResult, mysql_errno) {
1011 auto* data = Native::data<AsyncMysqlErrorResult>(this_);
1012 return data->m_op->mysql_errno();
1015 static String HHVM_METHOD(AsyncMysqlErrorResult, mysql_error) {
1016 auto* data = Native::data<AsyncMysqlErrorResult>(this_);
1017 return data->m_op->mysql_error();
1020 static String HHVM_METHOD(AsyncMysqlErrorResult, mysql_normalize_error) {
1021 auto* data = Native::data<AsyncMysqlErrorResult>(this_);
1022 return data->m_op->mysql_normalize_error();
1025 static String HHVM_METHOD(AsyncMysqlErrorResult, failureType) {
1026 auto* data = Native::data<AsyncMysqlErrorResult>(this_);
1027 return data->m_op->resultString().toString();
1030 ///////////////////////////////////////////////////////////////////////////////
1031 // class AsyncMysqlQueryErrorResult
1033 Class* AsyncMysqlQueryErrorResult::s_class = nullptr;
1034 const StaticString AsyncMysqlQueryErrorResult::s_className(
1035 "AsyncMysqlQueryErrorResult");
1037 IMPLEMENT_GET_CLASS(AsyncMysqlQueryErrorResult)
1039 Object AsyncMysqlQueryErrorResult::newInstance(
1040 std::shared_ptr<am::Operation> op,
1041 db::ClientPerfStats values,
1042 req::ptr<c_Vector> results) {
1043 Object ret{getClass()};
1044 Native::data<AsyncMysqlQueryErrorResult>(ret)
1045 ->create(std::move(op), std::move(values), results);
1046 return ret;
1049 AsyncMysqlQueryErrorResult::AsyncMysqlQueryErrorResult() {
1050 static_assert(offsetof(AsyncMysqlQueryErrorResult, m_parent) +
1051 sizeof(AsyncMysqlErrorResult) == sizeof(AsyncMysqlQueryErrorResult),
1052 "m_parent must be the last member of AsyncMysqlQueryErrorResult");
1055 void AsyncMysqlQueryErrorResult::sweep() {
1056 m_parent.sweep();
1059 void AsyncMysqlQueryErrorResult::create(std::shared_ptr<am::Operation> op,
1060 db::ClientPerfStats stats,
1061 req::ptr<c_Vector> results) {
1062 m_parent.create(std::move(op), std::move(stats));
1063 m_query_results = results;
1066 static int HHVM_METHOD(AsyncMysqlQueryErrorResult, numSuccessfulQueries) {
1067 auto* data = Native::data<AsyncMysqlQueryErrorResult>(this_);
1068 return std::dynamic_pointer_cast<am::FetchOperation>(data->m_parent.m_op)
1069 ->numQueriesExecuted();
1072 static Object HHVM_METHOD(AsyncMysqlQueryErrorResult, getSuccessfulResults) {
1073 auto* data = Native::data<AsyncMysqlQueryErrorResult>(this_);
1074 return Object(data->m_query_results);
1077 ///////////////////////////////////////////////////////////////////////////////
1078 // class AsyncMysqlQueryResult
1080 Class* AsyncMysqlQueryResult::s_class = nullptr;
1081 const StaticString AsyncMysqlQueryResult::s_className("AsyncMysqlQueryResult");
1083 IMPLEMENT_GET_CLASS(AsyncMysqlQueryResult)
1085 void AsyncMysqlQueryResult::sweep() {
1086 m_op.reset();
1087 m_query_result.reset();
1090 Object AsyncMysqlQueryResult::newInstance(std::shared_ptr<am::Operation> op,
1091 db::ClientPerfStats stats,
1092 am::QueryResult query_result,
1093 bool noIndexUsed) {
1094 Object ret{ getClass() };
1095 Native::data<AsyncMysqlQueryResult>(ret)->create(
1096 std::move(op), std::move(stats), std::move(query_result), noIndexUsed);
1097 return ret;
1100 void AsyncMysqlQueryResult::create(std::shared_ptr<am::Operation> op,
1101 db::ClientPerfStats stats,
1102 am::QueryResult query_result,
1103 bool noIndexUsed) {
1104 AsyncMysqlResult::create(std::move(op), std::move(stats));
1105 m_query_result = std::make_unique<am::QueryResult>(std::move(query_result));
1106 m_no_index_used = noIndexUsed;
1107 m_field_index = req::make_shared<FieldIndex>(m_query_result->getRowFields());
1110 EXTENDS_ASYNC_MYSQL_RESULT(AsyncMysqlQueryResult)
1112 static int64_t HHVM_METHOD(AsyncMysqlQueryResult, lastInsertId) {
1113 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
1114 return data->m_query_result->lastInsertId();
1117 static int64_t HHVM_METHOD(AsyncMysqlQueryResult, numRowsAffected) {
1118 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
1119 return data->m_query_result->numRowsAffected();
1122 static int64_t HHVM_METHOD(AsyncMysqlQueryResult, numRows) {
1123 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
1124 return data->m_query_result->numRows();
1126 static Object HHVM_METHOD(AsyncMysqlQueryResult, vectorRows) {
1127 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
1128 return data->buildRows(false /* as_maps */, false /* typed */);
1131 static Object HHVM_METHOD(AsyncMysqlQueryResult, mapRows) {
1132 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
1133 return data->buildRows(true /* as_maps */, false /* typed */);
1136 static Object HHVM_METHOD(AsyncMysqlQueryResult, vectorRowsTyped) {
1137 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
1138 return data->buildRows(false /* as_maps */, true /* typed */);
1141 static Object HHVM_METHOD(AsyncMysqlQueryResult, mapRowsTyped) {
1142 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
1143 return data->buildRows(true /* as_maps */, true /* typed */);
1146 static Object HHVM_METHOD(AsyncMysqlQueryResult, rowBlocks) {
1147 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
1148 auto ret = req::make<c_Vector>();
1149 auto row_blocks = data->m_query_result->stealRows();
1150 ret->reserve(row_blocks.size());
1152 for (auto& row_block : row_blocks) {
1153 ret->add(AsyncMysqlRowBlock::newInstance(&row_block,
1154 data->m_field_index));
1156 return Object{std::move(ret)};
1159 static bool HHVM_METHOD(AsyncMysqlQueryResult, noIndexUsed) {
1160 auto* data = Native::data<AsyncMysqlQueryResult>(this_);
1161 return data->m_no_index_used;
1164 namespace {
1165 Variant buildTypedValue(const am::RowFields* row_fields,
1166 const am::Row& row,
1167 int field_num,
1168 bool typed_values) {
1169 if (row.isNull(field_num)) {
1170 return init_null();
1173 // The underlying library may return zero length null ptr's to
1174 // indicate an empty string (since the isNull check above would tell
1175 // if it were actually NULL).
1176 String string_value =
1177 (row[field_num].data() == nullptr && row[field_num].size() == 0)
1178 ? empty_string()
1179 : String(row[field_num].data(), row[field_num].size(), CopyString);
1181 if (!typed_values) {
1182 return string_value;
1185 return mysql_makevalue(string_value, row_fields->getFieldType(field_num));
1189 Object AsyncMysqlQueryResult::buildRows(bool as_maps, bool typed_values) {
1190 auto ret = req::make<c_Vector>();
1191 ret->reserve(m_query_result->numRows());
1192 for (const auto& row : *m_query_result) {
1193 if (as_maps) {
1194 auto row_map = req::make<c_Map>();
1195 for (int i = 0; i < row.size(); ++i) {
1196 row_map->set(
1197 m_field_index->getFieldString(i),
1198 buildTypedValue(
1199 m_query_result->getRowFields(), row, i, typed_values));
1201 ret->add(Variant(std::move(row_map)));
1202 } else {
1203 auto row_vector = req::make<c_Vector>();
1204 row_vector->reserve(row.size());
1205 for (int i = 0; i < row.size(); ++i) {
1206 row_vector->add(buildTypedValue(
1207 m_query_result->getRowFields(), row, i, typed_values));
1209 ret->add(Variant(std::move(row_vector)));
1212 return Object(std::move(ret));
1215 FieldIndex::FieldIndex(const am::RowFields* row_fields) {
1216 if (row_fields == nullptr)
1217 return;
1218 field_names_.reserve(row_fields->numFields());
1219 for (int i = 0; i < row_fields->numFields(); ++i) {
1220 auto name = String(row_fields->fieldName(i).str());
1221 field_names_.push_back(name);
1222 field_name_map_[name] = i;
1226 size_t FieldIndex::getFieldIndex(String field_name) const {
1227 auto it = field_name_map_.find(field_name);
1228 if (it == field_name_map_.end()) {
1229 SystemLib::throwInvalidArgumentExceptionObject(
1230 "Given field name doesn't exist");
1232 return it->second;
1235 String FieldIndex::getFieldString(size_t field_index) const {
1236 // Leaving out of bounds to be thrown by the vector in case needed
1237 return field_names_.at(field_index);
1240 namespace {
1241 void throwAsyncMysqlException(const char* exception_type,
1242 std::shared_ptr<am::Operation> op,
1243 db::ClientPerfStats clientStats) {
1244 auto error =
1245 AsyncMysqlErrorResult::newInstance(op, std::move(clientStats));
1247 assertx(op->result() == am::OperationResult::Failed ||
1248 op->result() == am::OperationResult::TimedOut ||
1249 op->result() == am::OperationResult::Cancelled);
1251 Array params;
1252 params.append(std::move(error));
1253 throw_object(exception_type, params, true /* init */);
1256 void throwAsyncMysqlQueryException(const char* exception_type,
1257 std::shared_ptr<am::Operation> op,
1258 db::ClientPerfStats clientStats,
1259 req::ptr<c_Vector> res) {
1260 auto error = AsyncMysqlQueryErrorResult::newInstance(
1261 op, std::move(clientStats), res);
1263 assertx(op->result() == am::OperationResult::Failed ||
1264 op->result() == am::OperationResult::TimedOut ||
1265 op->result() == am::OperationResult::Cancelled);
1267 Array params;
1268 params.append(std::move(error));
1269 throw_object(exception_type, params, true /* init */);
1273 void AsyncMysqlConnectEvent::unserialize(Cell& result) {
1274 if (m_op->ok()) {
1275 auto ret = AsyncMysqlConnection::newInstance(
1276 m_op->releaseConnection(), m_op, std::move(m_clientStats));
1278 cellCopy(make_tv<KindOfObject>(ret.detach()), result);
1279 } else {
1280 throwAsyncMysqlException("AsyncMysqlConnectException", m_op,
1281 std::move(m_clientStats));
1285 void AsyncMysqlQueryEvent::unserialize(Cell& result) {
1286 // Retrieve the original conn and return the underlying connection
1287 // to it.
1288 assertx(getPrivData()->instanceof(AsyncMysqlConnection::getClass()));
1289 auto* conn = Native::data<AsyncMysqlConnection>(getPrivData());
1290 conn->setConnection(m_query_op->releaseConnection());
1292 if (m_query_op->ok()) {
1293 auto query_result = m_query_op->stealQueryResult();
1294 auto ret = AsyncMysqlQueryResult::newInstance(
1295 m_query_op, std::move(m_clientStats), std::move(query_result),
1296 m_query_op->noIndexUsed());
1297 cellCopy(make_tv<KindOfObject>(ret.detach()), result);
1298 } else {
1299 throwAsyncMysqlQueryException("AsyncMysqlQueryException",
1300 m_query_op,
1301 std::move(m_clientStats),
1302 req::make<c_Vector>());
1306 void AsyncMysqlMultiQueryEvent::unserialize(Cell& result) {
1307 // Same as unserialize from AsyncMysqlQueryEvent but the result is a
1308 // vector of query results
1309 if (getPrivData() != nullptr) {
1310 assertx(getPrivData()->instanceof(AsyncMysqlConnection::getClass()));
1311 auto* conn = Native::data<AsyncMysqlConnection>(getPrivData());
1312 conn->setConnection(m_multi_op->releaseConnection());
1315 // Retrieving the results for all executed queries
1316 auto results = req::make<c_Vector>();
1317 std::vector<am::QueryResult> query_results = m_multi_op->stealQueryResults();
1318 results->reserve(query_results.size());
1319 for (int i = 0; i < query_results.size(); ++i) {
1320 auto ret = AsyncMysqlQueryResult::newInstance(m_multi_op, m_clientStats,
1321 std::move(query_results[i]),
1322 m_multi_op->noIndexUsed());
1323 results->add(std::move(ret));
1325 query_results.clear();
1327 if (m_multi_op->ok()) {
1328 cellDup(make_tv<KindOfObject>(results.get()), result);
1329 } else {
1330 throwAsyncMysqlQueryException("AsyncMysqlQueryException", m_multi_op,
1331 std::move(m_clientStats), results);
1335 ///////////////////////////////////////////////////////////////////////////////
1336 // class AsyncMysqlRowBlock
1338 Class* AsyncMysqlRowBlock::s_class = nullptr;
1339 const StaticString AsyncMysqlRowBlock::s_className("AsyncMysqlRowBlock");
1341 IMPLEMENT_GET_CLASS(AsyncMysqlRowBlock)
1343 Object AsyncMysqlRowBlock::newInstance(am::RowBlock* row_block,
1344 req::shared_ptr<FieldIndex> indexer) {
1345 Object ret{AsyncMysqlRowBlock::getClass()};
1346 auto* data = Native::data<AsyncMysqlRowBlock>(ret);
1347 data->m_row_block.reset(new am::RowBlock(std::move(*row_block)));
1348 data->m_field_index = indexer;
1349 return ret;
1352 void AsyncMysqlRowBlock::sweep() {
1353 m_row_block.reset();
1356 size_t AsyncMysqlRowBlock::getIndexFromVariant(const Variant& field) {
1357 if (field.isInteger()) {
1358 return field.toInt64();
1359 } else if (field.isString()) {
1360 return m_field_index->getFieldIndex(field.toString());
1362 SystemLib::throwInvalidArgumentExceptionObject(
1363 "Only integer or string field names may be used with RowBlock");
1366 // The String conversion allows `NULL` to ""
1367 template <>
1368 folly::StringPiece AsyncMysqlRowBlock::getFieldAs(int64_t row,
1369 const Variant& field) {
1370 auto index = getIndexFromVariant(field);
1371 try {
1372 // Note that for String before you return to PHP you need to copy it into
1373 // HPHP::String.
1374 return m_row_block->getField<folly::StringPiece>(row, index);
1376 catch (std::range_error& excep) {
1377 SystemLib::throwBadMethodCallExceptionObject(
1378 std::string("Error during conversion: ") + excep.what());
1382 template <typename FieldType>
1383 FieldType AsyncMysqlRowBlock::getFieldAs(int64_t row, const Variant& field) {
1384 auto index = getIndexFromVariant(field);
1386 if (m_row_block->isNull(row, index)) {
1387 SystemLib::throwBadMethodCallExceptionObject(
1388 "Field value needs to be non-null.");
1390 try {
1391 return m_row_block->getField<FieldType>(row, index);
1393 catch (std::range_error& excep) {
1394 SystemLib::throwBadMethodCallExceptionObject(
1395 std::string("Error during conversion: ") + excep.what());
1399 static Variant
1400 HHVM_METHOD(AsyncMysqlRowBlock, at, int64_t row, const Variant& field) {
1401 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1402 auto col_index = data->getIndexFromVariant(field);
1403 return buildTypedValue(
1404 data->m_row_block->getRowFields(),
1405 data->m_row_block->getRow(row),
1406 col_index,
1407 true);
1410 static int64_t HHVM_METHOD(
1411 AsyncMysqlRowBlock,
1412 getFieldAsInt,
1413 int64_t row,
1414 const Variant& field) {
1415 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1416 return data->getFieldAs<int64_t>(row, field);
1419 static double HHVM_METHOD(
1420 AsyncMysqlRowBlock,
1421 getFieldAsDouble,
1422 int64_t row,
1423 const Variant& field) {
1424 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1425 return data->getFieldAs<double>(row, field);
1428 static String HHVM_METHOD(
1429 AsyncMysqlRowBlock,
1430 getFieldAsString,
1431 int64_t row,
1432 const Variant& field) {
1433 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1434 auto val = data->getFieldAs<folly::StringPiece>(row, field);
1435 // Cannot use the String constructor directly, as it has subtle different
1436 // behavior in the case where ptr is null, and length is 0, and it breaks flib
1437 // to change that.
1438 return String::attach(StringData::Make(val.data(), val.size(), CopyString));
1441 static bool
1442 HHVM_METHOD(AsyncMysqlRowBlock, isNull, int64_t row, const Variant& field) {
1443 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1444 return data->m_row_block->isNull(row, data->getIndexFromVariant(field));
1447 static int64_t
1448 HHVM_METHOD(AsyncMysqlRowBlock, fieldType, const Variant& field) {
1449 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1450 return data->m_row_block->getFieldType(data->getIndexFromVariant(field));
1453 static int64_t
1454 HHVM_METHOD(AsyncMysqlRowBlock, fieldFlags, const Variant& field) {
1455 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1456 return data->m_row_block->getFieldFlags(data->getIndexFromVariant(field));
1459 static String HHVM_METHOD(AsyncMysqlRowBlock, fieldName, int64_t field_id) {
1460 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1461 return data->m_field_index->getFieldString(field_id);
1464 static bool HHVM_METHOD(AsyncMysqlRowBlock, isEmpty) {
1465 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1466 return data->m_row_block->empty();
1469 static int64_t HHVM_METHOD(AsyncMysqlRowBlock, fieldsCount) {
1470 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1471 return data->m_row_block->numFields();
1474 static int64_t HHVM_METHOD(AsyncMysqlRowBlock, count) {
1475 auto* data = Native::data<AsyncMysqlRowBlock>(this_);
1476 return data->m_row_block->numRows();
1479 static Object HHVM_METHOD(AsyncMysqlRowBlock, getRow, int64_t row_no) {
1480 return AsyncMysqlRow::newInstance(Object{this_}, row_no);
1483 static Object HHVM_METHOD(AsyncMysqlRowBlock, getIterator) {
1484 return AsyncMysqlRowBlockIterator::newInstance(Object{this_}, 0);
1487 ///////////////////////////////////////////////////////////////////////////////
1488 // class AsyncMysqlRowBlockIterator
1490 Class* AsyncMysqlRowBlockIterator::s_class = nullptr;
1491 const StaticString AsyncMysqlRowBlockIterator::s_className(
1492 "AsyncMysqlRowBlockIterator");
1494 IMPLEMENT_GET_CLASS(AsyncMysqlRowBlockIterator)
1496 Object AsyncMysqlRowBlockIterator::newInstance(Object row_block,
1497 size_t row_number) {
1498 Object ret{getClass()};
1499 auto* data = Native::data<AsyncMysqlRowBlockIterator>(ret);
1500 data->m_row_block = row_block;
1501 data->m_row_number = row_number;
1502 return ret;
1505 static void HHVM_METHOD(AsyncMysqlRowBlockIterator, next) {
1506 auto* data = Native::data<AsyncMysqlRowBlockIterator>(this_);
1507 data->m_row_number++;
1510 static bool HHVM_METHOD(AsyncMysqlRowBlockIterator, valid) {
1511 auto* data = Native::data<AsyncMysqlRowBlockIterator>(this_);
1513 static_assert(
1514 std::is_unsigned<decltype(data->m_row_number)>::value,
1515 "m_row_number should be unsigned");
1516 int64_t count = HHVM_MN(AsyncMysqlRowBlock, count)(data->m_row_block.get());
1517 return data->m_row_number < count;
1520 static Object HHVM_METHOD(AsyncMysqlRowBlockIterator, current) {
1521 auto* data = Native::data<AsyncMysqlRowBlockIterator>(this_);
1523 if (!HHVM_MN(AsyncMysqlRowBlockIterator, valid)(this_)) {
1524 throw_iterator_not_valid();
1526 return HHVM_MN(AsyncMysqlRowBlock, getRow)(
1527 data->m_row_block.get(), data->m_row_number);
1530 static int64_t HHVM_METHOD(AsyncMysqlRowBlockIterator, key) {
1531 auto* data = Native::data<AsyncMysqlRowBlockIterator>(this_);
1532 return data->m_row_number;
1535 static void HHVM_METHOD(AsyncMysqlRowBlockIterator, rewind) {
1536 auto* data = Native::data<AsyncMysqlRowBlockIterator>(this_);
1537 data->m_row_number = 0;
1540 ///////////////////////////////////////////////////////////////////////////////
1541 // class AsyncMysqlRow
1543 Class* AsyncMysqlRow::s_class = nullptr;
1544 const StaticString AsyncMysqlRow::s_className("AsyncMysqlRow");
1546 IMPLEMENT_GET_CLASS(AsyncMysqlRow)
1548 Object AsyncMysqlRow::newInstance(Object row_block, size_t row_number) {
1549 Object ret{getClass()};
1550 auto* data = Native::data<AsyncMysqlRow>(ret);
1551 data->m_row_block = row_block;
1552 data->m_row_number = row_number;
1553 return ret;
1556 #define ROW_BLOCK(method, ...) \
1557 HHVM_MN(AsyncMysqlRowBlock, method)(data->m_row_block.get(), __VA_ARGS__)
1559 static Variant HHVM_METHOD(AsyncMysqlRow, at, const Variant& field) {
1560 auto* data = Native::data<AsyncMysqlRow>(this_);
1561 return ROW_BLOCK(at, data->m_row_number, field);
1564 static int64_t HHVM_METHOD(AsyncMysqlRow, getFieldAsInt, const Variant& field) {
1565 auto* data = Native::data<AsyncMysqlRow>(this_);
1566 return ROW_BLOCK(getFieldAsInt, data->m_row_number, field);
1569 static double
1570 HHVM_METHOD(AsyncMysqlRow, getFieldAsDouble, const Variant& field) {
1571 auto* data = Native::data<AsyncMysqlRow>(this_);
1572 return ROW_BLOCK(getFieldAsDouble, data->m_row_number, field);
1575 static String
1576 HHVM_METHOD(AsyncMysqlRow, getFieldAsString, const Variant& field) {
1577 auto* data = Native::data<AsyncMysqlRow>(this_);
1578 return ROW_BLOCK(getFieldAsString, data->m_row_number, field);
1581 static bool HHVM_METHOD(AsyncMysqlRow, isNull, const Variant& field) {
1582 auto* data = Native::data<AsyncMysqlRow>(this_);
1583 return ROW_BLOCK(isNull, data->m_row_number, field);
1586 static int64_t HHVM_METHOD(AsyncMysqlRow, fieldType, const Variant& field) {
1587 auto* data = Native::data<AsyncMysqlRow>(this_);
1588 return ROW_BLOCK(fieldType, field);
1591 static int64_t HHVM_METHOD(AsyncMysqlRow, count) {
1592 auto* data = Native::data<AsyncMysqlRow>(this_);
1593 return HHVM_MN(AsyncMysqlRowBlock, fieldsCount)(data->m_row_block.get());
1596 static Object HHVM_METHOD(AsyncMysqlRow, getIterator) {
1597 return AsyncMysqlRowIterator::newInstance(Object{this_}, 0);
1600 #undef ROW_BLOCK
1602 ///////////////////////////////////////////////////////////////////////////////
1603 // class AsyncMysqlRowIterator
1605 Class* AsyncMysqlRowIterator::s_class = nullptr;
1606 const StaticString AsyncMysqlRowIterator::s_className("AsyncMysqlRowIterator");
1608 IMPLEMENT_GET_CLASS(AsyncMysqlRowIterator)
1610 Object AsyncMysqlRowIterator::newInstance(Object row,
1611 size_t field_number) {
1612 Object ret{getClass()};
1613 auto* data = Native::data<AsyncMysqlRowIterator>(ret);
1614 data->m_row = row;
1615 data->m_field_number = field_number;
1616 return ret;
1619 static void HHVM_METHOD(AsyncMysqlRowIterator, next) {
1620 auto* data = Native::data<AsyncMysqlRowIterator>(this_);
1621 data->m_field_number++;
1624 static bool HHVM_METHOD(AsyncMysqlRowIterator, valid) {
1625 auto* data = Native::data<AsyncMysqlRowIterator>(this_);
1627 static_assert(
1628 std::is_unsigned<decltype(data->m_field_number)>::value,
1629 "m_field_number should be unsigned");
1630 int64_t count = HHVM_MN(AsyncMysqlRow, count)(data->m_row.get());
1631 return data->m_field_number < count;
1634 /*?? return as string? */
1635 static String HHVM_METHOD(AsyncMysqlRowIterator, current) {
1636 auto* data = Native::data<AsyncMysqlRowIterator>(this_);
1637 return HHVM_MN(AsyncMysqlRow, getFieldAsString)(
1638 data->m_row.get(), (uint64_t)data->m_field_number);
1641 static int64_t HHVM_METHOD(AsyncMysqlRowIterator, key) {
1642 auto* data = Native::data<AsyncMysqlRowIterator>(this_);
1643 return data->m_field_number;
1646 static void HHVM_METHOD(AsyncMysqlRowIterator, rewind) {
1647 auto* data = Native::data<AsyncMysqlRowIterator>(this_);
1648 data->m_field_number = 0;
1651 ///////////////////////////////////////////////////////////////////////////////
1653 static const int64_t DISABLE_COPY_AND_SWEEP = Native::NDIFlags::NO_COPY |
1654 Native::NDIFlags::NO_SWEEP;
1656 static struct AsyncMysqlExtension final : Extension {
1657 AsyncMysqlExtension() : Extension("async_mysql") {}
1658 void moduleInit() override {
1659 // expose the mysql flags
1660 HHVM_RC_INT_SAME(NOT_NULL_FLAG);
1661 HHVM_RC_INT_SAME(PRI_KEY_FLAG);
1662 HHVM_RC_INT_SAME(UNIQUE_KEY_FLAG);
1663 HHVM_RC_INT_SAME(MULTIPLE_KEY_FLAG);
1664 HHVM_RC_INT_SAME(UNSIGNED_FLAG);
1665 HHVM_RC_INT_SAME(ZEROFILL_FLAG);
1666 HHVM_RC_INT_SAME(BINARY_FLAG);
1667 HHVM_RC_INT_SAME(AUTO_INCREMENT_FLAG);
1668 HHVM_RC_INT_SAME(ENUM_FLAG);
1669 HHVM_RC_INT_SAME(SET_FLAG);
1670 HHVM_RC_INT_SAME(BLOB_FLAG);
1671 HHVM_RC_INT_SAME(TIMESTAMP_FLAG);
1672 HHVM_RC_INT_SAME(NUM_FLAG);
1673 HHVM_RC_INT_SAME(NO_DEFAULT_VALUE_FLAG);
1675 // expose the mysql field types
1676 HHVM_RC_INT_SAME(MYSQL_TYPE_TINY);
1677 HHVM_RC_INT_SAME(MYSQL_TYPE_SHORT);
1678 HHVM_RC_INT_SAME(MYSQL_TYPE_LONG);
1679 HHVM_RC_INT_SAME(MYSQL_TYPE_INT24);
1680 HHVM_RC_INT_SAME(MYSQL_TYPE_LONGLONG);
1681 HHVM_RC_INT_SAME(MYSQL_TYPE_DECIMAL);
1682 HHVM_RC_INT_SAME(MYSQL_TYPE_NEWDECIMAL);
1683 HHVM_RC_INT_SAME(MYSQL_TYPE_FLOAT);
1684 HHVM_RC_INT_SAME(MYSQL_TYPE_DOUBLE);
1685 HHVM_RC_INT_SAME(MYSQL_TYPE_BIT);
1686 HHVM_RC_INT_SAME(MYSQL_TYPE_TIMESTAMP);
1687 HHVM_RC_INT_SAME(MYSQL_TYPE_DATE);
1688 HHVM_RC_INT_SAME(MYSQL_TYPE_TIME);
1689 HHVM_RC_INT_SAME(MYSQL_TYPE_DATETIME);
1690 HHVM_RC_INT_SAME(MYSQL_TYPE_YEAR);
1691 HHVM_RC_INT_SAME(MYSQL_TYPE_STRING);
1692 HHVM_RC_INT_SAME(MYSQL_TYPE_VAR_STRING);
1693 HHVM_RC_INT_SAME(MYSQL_TYPE_BLOB);
1694 HHVM_RC_INT_SAME(MYSQL_TYPE_SET);
1695 HHVM_RC_INT_SAME(MYSQL_TYPE_ENUM);
1696 HHVM_RC_INT_SAME(MYSQL_TYPE_GEOMETRY);
1697 HHVM_RC_INT_SAME(MYSQL_TYPE_NULL);
1699 HHVM_STATIC_ME(AsyncMysqlClient, setPoolsConnectionLimit);
1700 HHVM_STATIC_ME(AsyncMysqlClient, connect);
1701 HHVM_STATIC_ME(AsyncMysqlClient, connectWithOpts);
1702 HHVM_STATIC_ME(AsyncMysqlClient, connectAndQuery);
1703 HHVM_STATIC_ME(AsyncMysqlClient, adoptConnection);
1705 HHVM_ME(AsyncMysqlConnectionPool, __construct);
1706 HHVM_ME(AsyncMysqlConnectionPool, getPoolStats);
1707 HHVM_ME(AsyncMysqlConnectionPool, connect);
1708 HHVM_ME(AsyncMysqlConnectionPool, connectWithOpts);
1709 Native::registerNativeDataInfo<AsyncMysqlConnectionPool>(
1710 AsyncMysqlConnectionPool::s_className.get(), Native::NDIFlags::NO_COPY);
1712 HHVM_ME(AsyncMysqlClientStats, ioEventLoopMicrosAvg);
1713 HHVM_ME(AsyncMysqlClientStats, callbackDelayMicrosAvg);
1715 HHVM_ME(AsyncMysqlClientStats, ioThreadBusyMicrosAvg);
1716 HHVM_ME(AsyncMysqlClientStats, ioThreadIdleMicrosAvg);
1717 HHVM_ME(AsyncMysqlClientStats, notificationQueueSize);
1718 Native::registerNativeDataInfo<AsyncMysqlClientStats>(
1719 AsyncMysqlClientStats::s_className.get());
1721 Native::registerNativeDataInfo<MySSLContextProvider>(
1722 MySSLContextProvider::s_className.get());
1723 HHVM_ME(MySSLContextProvider, isValid);
1725 HHVM_ME(AsyncMysqlConnection, query);
1726 HHVM_ME(AsyncMysqlConnection, queryf);
1727 HHVM_ME(AsyncMysqlConnection, multiQuery);
1728 HHVM_ME(AsyncMysqlConnection, escapeString);
1729 HHVM_ME(AsyncMysqlConnection, close);
1730 HHVM_ME(AsyncMysqlConnection, releaseConnection);
1731 HHVM_ME(AsyncMysqlConnection, isValid);
1732 HHVM_ME(AsyncMysqlConnection, serverInfo);
1733 HHVM_ME(AsyncMysqlConnection, sslSessionReused);
1734 HHVM_ME(AsyncMysqlConnection, isSSL);
1735 HHVM_ME(AsyncMysqlConnection, warningCount);
1736 HHVM_ME(AsyncMysqlConnection, host);
1737 HHVM_ME(AsyncMysqlConnection, port);
1738 HHVM_ME(AsyncMysqlConnection, setReusable);
1739 HHVM_ME(AsyncMysqlConnection, isReusable);
1740 HHVM_ME(AsyncMysqlConnection, connectResult);
1741 HHVM_ME(AsyncMysqlConnection, lastActivityTime);
1743 Native::registerNativeDataInfo<AsyncMysqlConnection>(
1744 AsyncMysqlConnection::s_className.get(), Native::NDIFlags::NO_COPY);
1746 HHVM_ME(AsyncMysqlConnectResult, elapsedMicros);
1747 HHVM_ME(AsyncMysqlConnectResult, startTime);
1748 HHVM_ME(AsyncMysqlConnectResult, endTime);
1749 HHVM_ME(AsyncMysqlConnectResult, clientStats);
1750 Native::registerNativeDataInfo<AsyncMysqlConnectResult>(
1751 AsyncMysqlConnectResult::s_className.get(), Native::NDIFlags::NO_COPY);
1753 HHVM_ME(AsyncMysqlErrorResult, elapsedMicros);
1754 HHVM_ME(AsyncMysqlErrorResult, startTime);
1755 HHVM_ME(AsyncMysqlErrorResult, endTime);
1756 HHVM_ME(AsyncMysqlErrorResult, clientStats);
1757 HHVM_ME(AsyncMysqlErrorResult, mysql_errno);
1758 HHVM_ME(AsyncMysqlErrorResult, mysql_error);
1759 HHVM_ME(AsyncMysqlErrorResult, mysql_normalize_error);
1760 HHVM_ME(AsyncMysqlErrorResult, failureType);
1761 Native::registerNativeDataInfo<AsyncMysqlErrorResult>(
1762 AsyncMysqlErrorResult::s_className.get(), Native::NDIFlags::NO_COPY);
1764 HHVM_ME(AsyncMysqlQueryErrorResult, numSuccessfulQueries);
1765 HHVM_ME(AsyncMysqlQueryErrorResult, getSuccessfulResults);
1766 Native::registerNativeDataInfo<AsyncMysqlQueryErrorResult>(
1767 AsyncMysqlQueryErrorResult::s_className.get(),
1768 Native::NDIFlags::NO_COPY);
1770 HHVM_ME(AsyncMysqlQueryResult, elapsedMicros);
1771 HHVM_ME(AsyncMysqlQueryResult, startTime);
1772 HHVM_ME(AsyncMysqlQueryResult, endTime);
1773 HHVM_ME(AsyncMysqlQueryResult, clientStats);
1774 HHVM_ME(AsyncMysqlQueryResult, numRowsAffected);
1775 HHVM_ME(AsyncMysqlQueryResult, lastInsertId);
1776 HHVM_ME(AsyncMysqlQueryResult, numRows);
1777 HHVM_ME(AsyncMysqlQueryResult, mapRows);
1778 HHVM_ME(AsyncMysqlQueryResult, vectorRows);
1779 HHVM_ME(AsyncMysqlQueryResult, mapRowsTyped);
1780 HHVM_ME(AsyncMysqlQueryResult, vectorRowsTyped);
1781 HHVM_ME(AsyncMysqlQueryResult, rowBlocks);
1782 HHVM_ME(AsyncMysqlQueryResult, noIndexUsed);
1783 Native::registerNativeDataInfo<AsyncMysqlQueryResult>(
1784 AsyncMysqlQueryResult::s_className.get(), Native::NDIFlags::NO_COPY);
1786 HHVM_ME(AsyncMysqlRowBlock, at);
1787 HHVM_ME(AsyncMysqlRowBlock, getFieldAsInt);
1788 HHVM_ME(AsyncMysqlRowBlock, getFieldAsDouble);
1789 HHVM_ME(AsyncMysqlRowBlock, getFieldAsString);
1790 HHVM_ME(AsyncMysqlRowBlock, isNull);
1791 HHVM_ME(AsyncMysqlRowBlock, fieldType);
1792 HHVM_ME(AsyncMysqlRowBlock, fieldFlags);
1793 HHVM_ME(AsyncMysqlRowBlock, fieldName);
1794 HHVM_ME(AsyncMysqlRowBlock, isEmpty);
1795 HHVM_ME(AsyncMysqlRowBlock, fieldsCount);
1796 HHVM_ME(AsyncMysqlRowBlock, count);
1797 HHVM_ME(AsyncMysqlRowBlock, getIterator);
1798 HHVM_ME(AsyncMysqlRowBlock, getRow);
1799 Native::registerNativeDataInfo<AsyncMysqlRowBlock>(
1800 AsyncMysqlRowBlock::s_className.get(), Native::NDIFlags::NO_COPY);
1802 HHVM_ME(AsyncMysqlRowBlockIterator, valid);
1803 HHVM_ME(AsyncMysqlRowBlockIterator, next);
1804 HHVM_ME(AsyncMysqlRowBlockIterator, current);
1805 HHVM_ME(AsyncMysqlRowBlockIterator, key);
1806 HHVM_ME(AsyncMysqlRowBlockIterator, rewind);
1807 Native::registerNativeDataInfo<AsyncMysqlRowBlockIterator>(
1808 AsyncMysqlRowBlockIterator::s_className.get(),
1809 DISABLE_COPY_AND_SWEEP);
1811 HHVM_ME(AsyncMysqlRow, at);
1812 HHVM_ME(AsyncMysqlRow, getFieldAsInt);
1813 HHVM_ME(AsyncMysqlRow, getFieldAsDouble);
1814 HHVM_ME(AsyncMysqlRow, getFieldAsString);
1815 HHVM_ME(AsyncMysqlRow, isNull);
1816 HHVM_ME(AsyncMysqlRow, fieldType);
1817 HHVM_ME(AsyncMysqlRow, count);
1818 HHVM_ME(AsyncMysqlRow, getIterator);
1819 Native::registerNativeDataInfo<AsyncMysqlRow>(
1820 AsyncMysqlRow::s_className.get(), DISABLE_COPY_AND_SWEEP);
1822 HHVM_ME(AsyncMysqlRowIterator, valid);
1823 HHVM_ME(AsyncMysqlRowIterator, next);
1824 HHVM_ME(AsyncMysqlRowIterator, current);
1825 HHVM_ME(AsyncMysqlRowIterator, key);
1826 HHVM_ME(AsyncMysqlRowIterator, rewind);
1827 Native::registerNativeDataInfo<AsyncMysqlRowIterator>(
1828 AsyncMysqlRowIterator::s_className.get(), DISABLE_COPY_AND_SWEEP);
1830 HHVM_ME(AsyncMysqlConnectionOptions, setConnectTimeout);
1831 HHVM_ME(AsyncMysqlConnectionOptions, setConnectAttempts);
1832 HHVM_ME(AsyncMysqlConnectionOptions, setTotalTimeout);
1833 HHVM_ME(AsyncMysqlConnectionOptions, setQueryTimeout);
1834 HHVM_ME(AsyncMysqlConnectionOptions, setConnectionAttributes);
1835 HHVM_ME(AsyncMysqlConnectionOptions, setSSLOptionsProvider);
1836 Native::registerNativeDataInfo<AsyncMysqlConnectionOptions>(
1837 AsyncMysqlConnectionOptions::s_className.get());
1839 loadSystemlib("mysqlrow");
1840 loadSystemlib("async_mysql_exceptions");
1841 loadSystemlib();
1843 void moduleLoad(const IniSetting::Map& ini, Hdf config) override {
1844 Config::Bind(
1845 HdfAsyncMysqlClientPoolSize,
1846 ini,
1847 config,
1848 "AsyncMysql.ClientPoolSize",
1851 } s_async_mysql_extension;
1853 ///////////////////////////////////////////////////////////////////////////////