2 +----------------------------------------------------------------------+
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"
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"
36 ///////////////////////////////////////////////////////////////////////////////
38 #define IMPLEMENT_GET_CLASS(cls) \
39 Class* cls::getClass() { \
40 if (s_class == nullptr) { \
41 s_class = Unit::lookupClass(s_className.get()); \
47 typedef am::ClientPool<am::AsyncMysqlClient, am::AsyncMysqlClientFactory>
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
);
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
;
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
));
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
));
139 std::shared_ptr
<am::SSLOptionsProviderBase
>
140 MySSLContextProvider::getSSLProvider() {
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() {
172 HHVM_METHOD(AsyncMysqlConnectionOptions
, setConnectTimeout
, int64_t timeout
) {
173 auto* data
= Native::data
<AsyncMysqlConnectionOptions
>(this_
);
174 data
->m_conn_opts
.setTimeout(am::Duration(timeout
));
178 HHVM_METHOD(AsyncMysqlConnectionOptions
, setConnectAttempts
, int32_t attempts
) {
179 auto* data
= Native::data
<AsyncMysqlConnectionOptions
>(this_
);
180 data
->m_conn_opts
.setConnectAttempts(attempts
);
184 HHVM_METHOD(AsyncMysqlConnectionOptions
, setTotalTimeout
, int64_t timeout
) {
185 auto* data
= Native::data
<AsyncMysqlConnectionOptions
>(this_
);
186 data
->m_conn_opts
.setTotalTimeout(am::Duration(timeout
));
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()) {
216 if (!sslContextProvider
.isObject() ||
217 !sslContextProvider
.toObject()->instanceof
218 (MySSLContextProvider::getClass())) {
219 SystemLib::throwInvalidArgumentExceptionObject(
220 "Wrong type: expected MySSLContextProvider argument");
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;
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())));
247 Class
* AsyncMysqlConnectionOptions::s_class
= nullptr;
248 const StaticString
AsyncMysqlConnectionOptions::s_className(
249 "AsyncMysqlConnectionOptions");
250 IMPLEMENT_GET_CLASS(AsyncMysqlConnectionOptions
)
252 //////////////////////////////////////////////////////////////////////////////
254 void HHVM_STATIC_METHOD(
256 setPoolsConnectionLimit
,
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
);
266 op
->setCallback([event
, clientPtr
](am::ConnectOperation
& /*op*/) {
268 event
->setClientStats(clientPtr
->collectPerfStats());
274 return Object
{event
->getWaitHandle()};
282 Object
HHVM_STATIC_METHOD(
287 const String
& dbname
,
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
),
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(
320 const String
& dbname
,
322 const String
& password
,
323 const Object
& asyncMysqlConnOpts
) {
324 am::ConnectionKey
key(
325 static_cast<std::string
>(host
),
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(
342 const Array
& queries
,
345 const String
& dbname
,
347 const String
& password
,
348 const Object
& asyncMysqlConnOpts
) {
349 am::ConnectionKey
key(
350 static_cast<std::string
>(host
),
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();
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
);
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
);
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());
384 query_op
->setCallback(am::resultAppender(appender_callback
));
387 LOG(ERROR
) << "Unexpected exception while executing Query";
393 return Object
{event
->getWaitHandle()};
395 LOG(ERROR
) << "Unexpected exception while creating Connection";
401 Object
HHVM_STATIC_METHOD(
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(
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
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
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");
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
);
468 am::AsyncConnectionPool::makePool(getClient(), pool_options
);
471 void AsyncMysqlConnectionPool::sweep() {
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
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(),
505 pool_stats
->numPoolHits(),
507 pool_stats
->numPoolMisses());
511 static Object
HHVM_METHOD(
512 AsyncMysqlConnectionPool
,
516 const String
& dbname
,
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
),
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
,
545 const String
& dbname
,
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
),
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
));
587 AsyncMysqlConnection::AsyncMysqlConnection() : m_port(0), m_closed(false) {}
589 void AsyncMysqlConnection::sweep() {
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())) {
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");
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(
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
);
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
);
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());
655 op
->setCallback(am::resultAppender(appender_callback
));
658 return Object
{event
->getWaitHandle()};
661 LOG(ERROR
) << "Unexpected exception while beginning ConnectOperation";
668 static Object
HHVM_METHOD(
669 AsyncMysqlConnection
,
672 int64_t timeout_micros
/* = -1 */) {
673 auto* data
= Native::data
<AsyncMysqlConnection
>(this_
);
677 am::Query::unsafe(static_cast<std::string
>(query
)),
681 static Object
HHVM_METHOD(
682 AsyncMysqlConnection
,
684 const String
& pattern
,
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);
710 for (ArrayIter
iter(args
); iter
; ++iter
) {
711 const Variant
& arg
= iter
.second();
712 if (scalarPush(query_args
, arg
)) {
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
)) {
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",
730 getDataTypeString(item
.getType()).c_str(),
734 query_args
.push_back(out
);
739 throw_invalid_argument(
740 "queryf parameters must be scalars, or Vectors of scalars. "
741 "Parameter %ld is a %s",
743 getDataTypeString(arg
.getType()).c_str()
748 this_
, am::Query(static_cast<std::string
>(pattern
), query_args
));
751 static Object
HHVM_METHOD(
752 AsyncMysqlConnection
,
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
);
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
);
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());
780 op
->setCallback(am::resultAppender(appender_callback
));
783 return Object
{event
->getWaitHandle()};
792 static bool HHVM_METHOD(AsyncMysqlConnection
, isValid
) {
793 auto* data
= Native::data
<AsyncMysqlConnection
>(this_
);
794 return data
->isValidConnection();
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());
806 static String
HHVM_METHOD(AsyncMysqlConnection
, serverInfo
) {
807 auto* data
= Native::data
<AsyncMysqlConnection
>(this_
);
810 if (data
->isValidConnection()) {
811 ret
= data
->m_conn
->serverInfo();
813 LOG(ERROR
) << "Accessing closed connection";
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_
);
838 if (data
->isValidConnection()) {
839 count
= data
->m_conn
->warningCount();
841 LOG(ERROR
) << "Accessing closed connection";
846 static String
HHVM_METHOD(AsyncMysqlConnection
, host
) {
847 auto* data
= Native::data
<AsyncMysqlConnection
>(this_
);
851 static int HHVM_METHOD(AsyncMysqlConnection
, port
) {
852 auto* data
= Native::data
<AsyncMysqlConnection
>(this_
);
856 static void HHVM_METHOD(AsyncMysqlConnection
, setReusable
, bool reusable
) {
857 auto* data
= Native::data
<AsyncMysqlConnection
>(this_
);
860 data
->m_conn
->setReusable(reusable
);
862 LOG(ERROR
) << "Accessing closed connection";
866 static bool HHVM_METHOD(AsyncMysqlConnection
, isReusable
) {
867 auto* data
= Native::data
<AsyncMysqlConnection
>(this_
);
870 return data
->m_conn
->isReusable();
872 LOG(ERROR
) << "Accessing closed connection";
877 static Variant
HHVM_METHOD(AsyncMysqlConnection
, connectResult
) {
878 auto* data
= Native::data
<AsyncMysqlConnection
>(this_
);
881 return AsyncMysqlConnectResult::newInstance(data
->m_op
,
882 data
->m_clientStats
);
884 LOG(ERROR
) << "ConnectResult only available when Connection created by "
890 static double HHVM_METHOD(AsyncMysqlConnection
, lastActivityTime
) {
891 auto* data
= Native::data
<AsyncMysqlConnection
>(this_
);
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;
898 LOG(ERROR
) << "Accessing closed connection";
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;
922 req::make
<MySQLResource
>(
923 std::make_shared
<MySQL
>(host
.c_str(),
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.");
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
));
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
));
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
);
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() {
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() {
1087 m_query_result
.reset();
1090 Object
AsyncMysqlQueryResult::newInstance(std::shared_ptr
<am::Operation
> op
,
1091 db::ClientPerfStats stats
,
1092 am::QueryResult query_result
,
1094 Object ret
{ getClass() };
1095 Native::data
<AsyncMysqlQueryResult
>(ret
)->create(
1096 std::move(op
), std::move(stats
), std::move(query_result
), noIndexUsed
);
1100 void AsyncMysqlQueryResult::create(std::shared_ptr
<am::Operation
> op
,
1101 db::ClientPerfStats stats
,
1102 am::QueryResult query_result
,
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
;
1165 Variant
buildTypedValue(const am::RowFields
* row_fields
,
1168 bool typed_values
) {
1169 if (row
.isNull(field_num
)) {
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)
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
) {
1194 auto row_map
= req::make
<c_Map
>();
1195 for (int i
= 0; i
< row
.size(); ++i
) {
1197 m_field_index
->getFieldString(i
),
1199 m_query_result
->getRowFields(), row
, i
, typed_values
));
1201 ret
->add(Variant(std::move(row_map
)));
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)
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");
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
);
1241 void throwAsyncMysqlException(const char* exception_type
,
1242 std::shared_ptr
<am::Operation
> op
,
1243 db::ClientPerfStats clientStats
) {
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
);
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
);
1268 params
.append(std::move(error
));
1269 throw_object(exception_type
, params
, true /* init */);
1273 void AsyncMysqlConnectEvent::unserialize(Cell
& result
) {
1275 auto ret
= AsyncMysqlConnection::newInstance(
1276 m_op
->releaseConnection(), m_op
, std::move(m_clientStats
));
1278 cellCopy(make_tv
<KindOfObject
>(ret
.detach()), result
);
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
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
);
1299 throwAsyncMysqlQueryException("AsyncMysqlQueryException",
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
);
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
;
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 ""
1368 folly::StringPiece
AsyncMysqlRowBlock::getFieldAs(int64_t row
,
1369 const Variant
& field
) {
1370 auto index
= getIndexFromVariant(field
);
1372 // Note that for String before you return to PHP you need to copy it into
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.");
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());
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
),
1410 static int64_t HHVM_METHOD(
1414 const Variant
& field
) {
1415 auto* data
= Native::data
<AsyncMysqlRowBlock
>(this_
);
1416 return data
->getFieldAs
<int64_t>(row
, field
);
1419 static double HHVM_METHOD(
1423 const Variant
& field
) {
1424 auto* data
= Native::data
<AsyncMysqlRowBlock
>(this_
);
1425 return data
->getFieldAs
<double>(row
, field
);
1428 static String
HHVM_METHOD(
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
1438 return String::attach(StringData::Make(val
.data(), val
.size(), CopyString
));
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
));
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
));
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
;
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_
);
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
;
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
);
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
);
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);
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
);
1615 data
->m_field_number
= field_number
;
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_
);
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");
1843 void moduleLoad(const IniSetting::Map
& ini
, Hdf config
) override
{
1845 HdfAsyncMysqlClientPoolSize
,
1848 "AsyncMysql.ClientPoolSize",
1851 } s_async_mysql_extension
;
1853 ///////////////////////////////////////////////////////////////////////////////