int64_t f_mysql_async_status(CVarRef link_identifier) { MySQL *mySQL = MySQL::Get(link_identifier); if (!mySQL || !mySQL->get()) { raise_warning("supplied argument is not a valid MySQL-Link resource"); return -1; } return mySQL->get()->async_op_status; }
static int64_t HHVM_FUNCTION(mysql_async_status, const Variant& link_identifier) { MySQL *mySQL = MySQL::Get(link_identifier); if (!mySQL || !mySQL->get()) { raise_warning("supplied argument is not a valid MySQL-Link resource"); return -1; } return mySQL->get()->async_op_status; }
Variant f_mysql_async_query_result(CVarRef link_identifier) { MySQL* mySQL = MySQL::Get(link_identifier); if (!mySQL) { raise_warning("supplied argument is not a valid MySQL-Link resource"); return Variant(Variant::NullInit()); } MYSQL* conn = mySQL->get(); if (!conn || (conn->async_op_status != ASYNC_OP_QUERY && conn->async_op_status != ASYNC_OP_UNSET)) { raise_warning("runtime/ext_mysql: attempt to check query result when query " "not executing"); return Variant(Variant::NullInit()); } int error = 0; auto status = mysql_real_query_nonblocking( conn, mySQL->m_async_query.data(), mySQL->m_async_query.size(), &error); if (status != NET_ASYNC_COMPLETE) { return Variant(Variant::NullInit()); } if (error) { return Variant(Variant::NullInit()); } mySQL->m_async_query.reset(); MYSQL_RES* mysql_result = mysql_use_result(conn); MySQLResult *r = NEWOBJ(MySQLResult)(mysql_result); r->setAsyncConnection(mySQL); Resource ret(r); return ret; }
Variant f_mysql_warning_count(CVarRef link_identifier /* = null */) { MySQL *mySQL = MySQL::Get(link_identifier); if (!mySQL) { raise_warning("supplied argument is not a valid MySQL-Link resource"); return false; } MYSQL *conn = mySQL->get(); if (conn) { return (int64_t)mysql_warning_count(conn); } return false; }
Variant f_mysql_error(CVarRef link_identifier /* = null */) { MySQL *mySQL = MySQL::Get(link_identifier); if (!mySQL) { raise_warning("supplied argument is not a valid MySQL-Link resource"); return false; } MYSQL *conn = mySQL->get(); if (conn) { return String(mysql_error(conn), CopyString); } if (mySQL->m_last_error_set) { return String(mySQL->m_last_error); } return false; }
Variant f_mysql_errno(const Variant& link_identifier /* = null */) { MySQL *mySQL = MySQL::Get(link_identifier); if (!mySQL) { raise_warning("supplied argument is not a valid MySQL-Link resource"); return false; } MYSQL *conn = mySQL->get(); if (conn) { return (int64_t)mysql_errno(conn); } if (mySQL->m_last_error_set) { return (int64_t)mySQL->m_last_errno; } return false; }
MYSQL *MySQL::GetConn(const Variant& link_identifier, MySQL **rconn /* = NULL */) { MySQL *mySQL = Get(link_identifier); MYSQL *ret = nullptr; if (mySQL) { ret = mySQL->get(); } if (ret == nullptr) { raise_warning("supplied argument is not a valid MySQL-Link resource"); } // Don't return a connection where mysql_real_connect() failed to most // f_mysql_* APIs (the ones that deal with errno where we do want to do this // anyway use MySQL::Get instead) as mysqlclient doesn't support passing // connections in that state and it can crash. if (mySQL && mySQL->m_last_error_set) { ret = nullptr; } else if (rconn) { *rconn = mySQL; } return ret; }
bool f_mysql_async_connect_completed(CVarRef link_identifier) { MySQL* mySQL = MySQL::Get(link_identifier); if (!mySQL) { raise_warning("supplied argument is not a valid MySQL-Link resource"); return true; } MYSQL* conn = mySQL->get(); if (conn->async_op_status != ASYNC_OP_CONNECT) { // Don't warn if we're in UNSET state (ie between queries, etc) if (conn->async_op_status != ASYNC_OP_UNSET) { raise_warning("runtime/ext_mysql: no pending async connect in progress"); } return true; } int error = 0; auto status = mysql_real_connect_nonblocking_run(conn, &error); return status == NET_ASYNC_COMPLETE; }
// This function takes an array of arrays, each of which is of the // form array($dbh, ...). The only thing that matters in the inner // arrays is the first element being a MySQL instance. It then // procedes to block for up to 'timeout' seconds, waiting for the // first actionable descriptor(s), which it then returns in the form // of the original arrays passed in. The intention is the caller // would include other information they care about in the tail of the // array so they can decide how to act on the // potentially-now-queryable descriptors. // // This function is a poor shadow of how the async library can be // used; for more complex cases, we'd use libevent and share our event // loop with other IO operations such as memcache ops, thrift calls, // etc. That said, this function is reasonably efficient for most use // cases. Variant f_mysql_async_wait_actionable(CVarRef items, double timeout) { size_t count = items.toArray().size(); if (count == 0 || timeout < 0) { return Array::Create(); } struct pollfd* fds = (struct pollfd*)calloc(count, sizeof(struct pollfd)); SCOPE_EXIT { free(fds); }; // Walk our input, determine what kind of poll() operation is // necessary for the descriptor in question, and put an entry into // fds. int nfds = 0; for (ArrayIter iter(items.toArray()); iter; ++iter) { Array entry = iter.second().toArray(); if (entry.size() < 1) { raise_warning("element %d did not have at least one entry", nfds); return Array::Create(); } MySQL* mySQL = entry.rvalAt(0).toResource().getTyped<MySQL>(); MYSQL* conn = mySQL->get(); if (conn->async_op_status == ASYNC_OP_UNSET) { raise_warning("runtime/ext_mysql: no pending async operation in " "progress"); return Array::Create(); } pollfd* fd = &fds[nfds++]; fd->fd = mysql_get_file_descriptor(conn); if (conn->net.async_blocking_state == NET_NONBLOCKING_READ) { fd->events = POLLIN; } else { fd->events = POLLOUT; } fd->revents = 0; } // The poll itself; either the timeout is hit or one or more of the // input fd's is ready. int timeout_millis = static_cast<long>(timeout * 1000); int res = poll(fds, nfds, timeout_millis); if (res == -1) { raise_warning("unable to poll [%d]: %s", errno, folly::errnoStr(errno).c_str()); return Array::Create(); } // Now just find the ones that are ready, and copy the corresponding // arrays from our input array into our return value. Array ret = Array::Create(); nfds = 0; for (ArrayIter iter(items.toArray()); iter; ++iter) { Array entry = iter.second().toArray(); if (entry.size() < 1) { raise_warning("element %d did not have at least one entry", nfds); return Array::Create(); } MySQL* mySQL = entry.rvalAt(0).toResource().getTyped<MySQL>(); MYSQL* conn = mySQL->get(); pollfd* fd = &fds[nfds++]; if (fd->fd != mysql_get_file_descriptor(conn)) { raise_warning("poll returned events out of order wtf"); continue; } if (fd->revents != 0) { ret.append(iter.second()); } } return ret; }