bool Connection::ping() { log_debug("ping()"); if (PQsendQuery(conn, "select 1") == 0) { log_debug("failed to send statement \"select 1\" to database in Connection::ping()"); return false; } while (true) { struct pollfd fd; fd.fd = PQsocket(conn); fd.events = POLLIN; log_debug("wait for input on fd " << fd.fd); if (::poll(&fd, 1, 10000) != 1) { log_debug("no data received in Connection::ping()"); return false; } log_debug("consumeInput"); if (PQconsumeInput(conn) == 0) { log_debug("PQconsumeInput failed in Connection::ping()"); return false; } log_debug("check PQisBusy"); while (PQisBusy(conn) == 0) { log_debug("PQgetResult"); PGresult* result = PQgetResult(conn); log_debug("PQgetResult => " << static_cast<void*>(result)); if (result == 0) return true; log_debug("PQfree"); PQclear(result); } } }
int pgut_wait(int num, PGconn *connections[], struct timeval *timeout) { /* all connections are busy. wait for finish */ while (!interrupted) { int i; fd_set mask; int maxsock; FD_ZERO(&mask); maxsock = -1; for (i = 0; i < num; i++) { int sock; if (connections[i] == NULL) continue; sock = PQsocket(connections[i]); if (sock >= 0) { FD_SET(sock, &mask); if (maxsock < sock) maxsock = sock; } } if (maxsock == -1) { errno = ENOENT; return -1; } i = wait_for_sockets(maxsock + 1, &mask, timeout); if (i == 0) break; /* timeout */ for (i = 0; i < num; i++) { if (connections[i] && FD_ISSET(PQsocket(connections[i]), &mask)) { PQconsumeInput(connections[i]); if (PQisBusy(connections[i])) continue; return i; } } } errno = EINTR; return -1; }
/* * Wait until we can read WAL stream, or timeout. * * Returns true if data has become available for reading, false if timed out * or interrupted by signal. * * This is based on pqSocketCheck. */ static bool libpq_select(int timeout_ms) { int ret; Assert(streamConn != NULL); if (PQsocket(streamConn) < 0) ereport(ERROR, (errcode_for_socket_access(), errmsg("socket not open"))); /* We use poll(2) if available, otherwise select(2) */ { #ifdef HAVE_POLL struct pollfd input_fd; input_fd.fd = PQsocket(streamConn); input_fd.events = POLLIN | POLLERR; input_fd.revents = 0; ret = poll(&input_fd, 1, timeout_ms); #else /* !HAVE_POLL */ fd_set input_mask; struct timeval timeout; struct timeval *ptr_timeout; FD_ZERO(&input_mask); FD_SET(PQsocket(streamConn), &input_mask); if (timeout_ms < 0) ptr_timeout = NULL; else { timeout.tv_sec = timeout_ms / 1000; timeout.tv_usec = (timeout_ms % 1000) * 1000; ptr_timeout = &timeout; } ret = select(PQsocket(streamConn) + 1, &input_mask, NULL, NULL, ptr_timeout); #endif /* HAVE_POLL */ } if (ret == 0 || (ret < 0 && errno == EINTR)) return false; if (ret < 0) ereport(ERROR, (errcode_for_socket_access(), errmsg("select() failed: %m"))); return true; }
bool DoConnect() { sql = PQconnectStart(GetDSN().c_str()); if (!sql) return false; if(PQstatus(sql) == CONNECTION_BAD) return false; if(PQsetnonblocking(sql, 1) == -1) return false; /* OK, we've initalised the connection, now to get it hooked into the socket engine * and then start polling it. */ this->fd = PQsocket(sql); if(this->fd <= -1) return false; if (!ServerInstance->SE->AddFd(this, FD_WANT_NO_WRITE | FD_WANT_NO_READ)) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "BUG: Couldn't add pgsql socket to socket engine"); return false; } /* Socket all hooked into the engine, now to tell PgSQL to start connecting */ return DoPoll(); }
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_handle_connect(switch_pgsql_handle_t *handle) { #ifdef SWITCH_HAVE_PGSQL if (handle->state == SWITCH_PGSQL_STATE_CONNECTED) { switch_pgsql_handle_disconnect(handle); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Re-connecting %s\n", handle->dsn); } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Connecting %s\n", handle->dsn); handle->con = PQconnectdb(handle->dsn); if (PQstatus(handle->con) != CONNECTION_OK) { char *err_str; if ((err_str = switch_pgsql_handle_get_error(handle))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s\n", err_str); switch_safe_free(err_str); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to connect to the database [%s]\n", handle->dsn); switch_pgsql_handle_disconnect(handle); } return SWITCH_PGSQL_FAIL; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Connected to [%s]\n", handle->dsn); handle->state = SWITCH_PGSQL_STATE_CONNECTED; handle->sock = PQsocket(handle->con); return SWITCH_PGSQL_SUCCESS; #else return SWITCH_PGSQL_FAIL; #endif }
int evpg_connect(struct evpg_cfg *config, const char *connstr) { int pgsock; int status; struct evpg_db_node *dbnode; void **usrdata; if (!(dbnode = calloc(sizeof(struct evpg_db_node), 1))) return -1; dbnode->dbconn = PQconnectStart(connstr); pgsock = PQsocket(dbnode->dbconn); /* set this dbnode into an active state since it is not ready to be used by the calling application */ evpg_set_active(config, dbnode); /* we want to pass both our config, and our node */ usrdata = malloc(sizeof(void *) * 2); usrdata[0] = config; usrdata[1] = dbnode; /* start the non-blocking connect event */ event_set(&dbnode->event, pgsock, EV_WRITE, (void *)evpg_connect_check, usrdata); event_add(&dbnode->event, 0); }
/* * MultiClientRegisterWait adds a connection to be waited upon, waiting for * executionStatus. */ void MultiClientRegisterWait(WaitInfo *waitInfo, TaskExecutionStatus executionStatus, int32 connectionId) { PGconn *connection = NULL; struct pollfd *pollfd = NULL; Assert(waitInfo->registeredWaiters < waitInfo->maxWaiters); if (executionStatus == TASK_STATUS_READY) { waitInfo->haveReadyWaiter = true; return; } else if (executionStatus == TASK_STATUS_ERROR) { waitInfo->haveFailedWaiter = true; return; } connection = ClientConnectionArray[connectionId]; pollfd = &waitInfo->pollfds[waitInfo->registeredWaiters]; pollfd->fd = PQsocket(connection); if (executionStatus == TASK_STATUS_SOCKET_READ) { pollfd->events = POLLERR | POLLIN; } else if (executionStatus == TASK_STATUS_SOCKET_WRITE) { pollfd->events = POLLERR | POLLOUT; } waitInfo->registeredWaiters++; }
PGresult * do_postgres_cCommand_execute_async(VALUE self, VALUE connection, PGconn *db, VALUE query) { PGresult *response; char* str = StringValuePtr(query); while ((response = PQgetResult(db))) { PQclear(response); } struct timeval start; int retval; gettimeofday(&start, NULL); retval = PQsendQuery(db, str); if (!retval) { if (PQstatus(db) != CONNECTION_OK) { PQreset(db); if (PQstatus(db) == CONNECTION_OK) { retval = PQsendQuery(db, str); } else { do_postgres_full_connect(connection, db); retval = PQsendQuery(db, str); } } if (!retval) { rb_raise(eDO_ConnectionError, "%s", PQerrorMessage(db)); } } int socket_fd = PQsocket(db); fd_set rset; while (1) { FD_ZERO(&rset); FD_SET(socket_fd, &rset); retval = rb_thread_select(socket_fd + 1, &rset, NULL, NULL, NULL); if (retval < 0) { rb_sys_fail(0); } if (retval == 0) { continue; } if (PQconsumeInput(db) == 0) { rb_raise(eDO_ConnectionError, "%s", PQerrorMessage(db)); } if (PQisBusy(db) == 0) { break; } } data_objects_debug(connection, query, &start); return PQgetResult(db); }
/* * set_connection_status_bad does not remove the given connection from the connection hash. * It simply shuts down the underlying socket. On success, it returns true. */ Datum set_connection_status_bad(PG_FUNCTION_ARGS) { char *nodeName = PG_GETARG_CSTRING(0); int32 nodePort = PG_GETARG_INT32(1); int socket = -1; int shutdownStatus = 0; int pqStatus PG_USED_FOR_ASSERTS_ONLY = 0; PGconn *connection = GetOrEstablishConnection(nodeName, nodePort); if (connection == NULL) { PG_RETURN_BOOL(false); } /* Prevent further reads/writes... */ socket = PQsocket(connection); shutdownStatus = shutdown(socket, SHUT_RDWR); if (shutdownStatus != 0) { ereport(ERROR, (errcode_for_socket_access(), errmsg("shutdown failed"))); } /* ... and make libpq notice by reading data. */ pqStatus = PQconsumeInput(connection); Assert(pqStatus == 0); /* expect failure */ PG_RETURN_BOOL(true); }
void PgStartNotifyEventSource(Pg_ConnectionId * connid) { /* Start the notify event source if it isn't already running */ if (!connid->notifier_running) { int pqsock = PQsocket(connid->conn); if (pqsock >= 0) { #if TCL_MAJOR_VERSION >= 8 Tcl_CreateChannelHandler(connid->notifier_channel, TCL_READABLE, Pg_Notify_FileHandler, (ClientData) connid); #else /* In Tcl 7.5 and 7.6, we need to gin up a Tcl_File. */ Tcl_File tclfile = Tcl_GetFile((ClientData) pqsock, TCL_UNIX_FD); Tcl_CreateFileHandler(tclfile, TCL_READABLE, Pg_Notify_FileHandler, (ClientData) connid); connid->notifier_socket = pqsock; #endif connid->notifier_running = 1; } } }
void PgNotifyTransferEvents(Pg_ConnectionId * connid) { PGnotify *notify; while ((notify = PQnotifies(connid->conn)) != NULL) { NotifyEvent *event = (NotifyEvent *) ckalloc(sizeof(NotifyEvent)); event->header.proc = Pg_Notify_EventProc; event->notify = notify; event->connid = connid; Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL); } /* * This is also a good place to check for unexpected closure of the * connection (ie, backend crash), in which case we must shut down the * notify event source to keep Tcl from trying to select() on the now- * closed socket descriptor. But don't kill on-connection-loss * events; in fact, register one. */ if (PQsocket(connid->conn) < 0) PgConnLossTransferEvents(connid); }
static void init_slot(ParallelSlot *slot, PGconn *conn) { slot->connection = conn; slot->isFree = true; slot->sock = PQsocket(conn); }
struct connection_struct* initDatabase(struct event_base* base) { struct connection_struct* database = malloc(sizeof(struct connection_struct)); database->query_count = 0; database->report_errors = 0; database->queries = NULL; database->last_query = NULL; database->conn = PQconnectdb(db_connect); if (PQstatus(database->conn) != CONNECTION_OK) { fprintf(stderr, "%s\n", PQerrorMessage(database->conn)); PQfinish(database->conn); exit(1); } else PQsetnonblocking(database->conn, 1); struct event* event = event_new(base, PQsocket(database->conn), EV_READ|EV_PERSIST, pq_event, database); event_add(event, NULL); if (all_databases == NULL) { all_databases = malloc(sizeof(struct database_list)); memset(all_databases, 0, sizeof(struct database_list)); all_databases->db = database; } else { struct database_list* node = all_databases; while (node->next) node = node->next; node->next = malloc(sizeof(struct database_list)); memset(node->next, 0, sizeof(struct database_list)); node->next->db = database; } return database; };
static void wait_for_flush(PlxFn *plx_fn, PGconn *pq_conn) { struct epoll_event listenev; struct epoll_event event; int res; res = PQflush(pq_conn); if (!res) return; if (res == -1) plx_error(plx_fn, "PQflush error %s", PQerrorMessage(pq_conn)); listenev.events = EPOLLOUT; listenev.data.fd = PQsocket(pq_conn); if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listenev.data.fd, &listenev) < 0) plx_error(plx_fn, "epoll: socket adding failed"); while (res) { CHECK_FOR_INTERRUPTS(); epoll_wait(epoll_fd, &event, 1, 1); res = PQflush(pq_conn); if (res == -1) { epoll_ctl(epoll_fd, EPOLL_CTL_DEL, listenev.data.fd, &listenev); plx_error(plx_fn, "%s", PQerrorMessage(pq_conn)); } } epoll_ctl(epoll_fd, EPOLL_CTL_DEL, listenev.data.fd, &listenev); }
/* * Create and register a new channel for the connection */ void PgSetConnectionId(Tcl_Interp *interp, PGconn *conn) { Tcl_Channel conn_chan; Pg_ConnectionId *connid; int i; connid = (Pg_ConnectionId *) ckalloc(sizeof(Pg_ConnectionId)); connid->conn = conn; connid->res_count = 0; connid->res_last = -1; connid->res_max = RES_START; connid->res_hardmax = RES_HARD_MAX; connid->res_copy = -1; connid->res_copyStatus = RES_COPY_NONE; connid->results = (PGresult **) ckalloc(sizeof(PGresult *) * RES_START); for (i = 0; i < RES_START; i++) connid->results[i] = NULL; connid->notify_list = NULL; connid->notifier_running = 0; sprintf(connid->id, "pgsql%d", PQsocket(conn)); #if TCL_MAJOR_VERSION >= 8 connid->notifier_channel = Tcl_MakeTcpClientChannel((ClientData) PQsocket(conn)); Tcl_RegisterChannel(NULL, connid->notifier_channel); #else connid->notifier_socket = -1; #endif #if TCL_MAJOR_VERSION == 7 && TCL_MINOR_VERSION == 5 /* Original signature (only seen in Tcl 7.5) */ conn_chan = Tcl_CreateChannel(&Pg_ConnType, connid->id, NULL, NULL, (ClientData) connid); #else /* Tcl 7.6 and later use this */ conn_chan = Tcl_CreateChannel(&Pg_ConnType, connid->id, (ClientData) connid, TCL_READABLE | TCL_WRITABLE); #endif Tcl_SetChannelOption(interp, conn_chan, "-buffering", "line"); Tcl_SetResult(interp, connid->id, TCL_VOLATILE); Tcl_RegisterChannel(interp, conn_chan); }
static PyObject * psyco_conn_fileno(connectionObject *self) { long int socket; EXC_IF_CONN_CLOSED(self); socket = (long int)PQsocket(self->pgconn); return PyInt_FromLong(socket); }
/* Blocks until more data is received from the server. You don't have to use * this if you have your own select loop. */ int db_client_wait(client_context_t context) { fd_set input_mask; FD_ZERO(&input_mask); int rep_fd = PQsocket(context->repl.conn); int max_fd = rep_fd; FD_SET(rep_fd, &input_mask); if (context->sql_conn) { int sql_fd = PQsocket(context->sql_conn); if (sql_fd > max_fd) max_fd = sql_fd; FD_SET(sql_fd, &input_mask); } struct timeval timeout; timeout.tv_sec = 1; timeout.tv_usec = 0; int ret = select(max_fd + 1, &input_mask, NULL, NULL, &timeout); if (ret == 0 || (ret < 0 && errno == EINTR)) { return 0; /* timeout or signal */ } if (ret < 0) { client_error(context, "select() failed: %s", strerror(errno)); return errno; } /* Data has arrived on the socket */ if (!PQconsumeInput(context->repl.conn)) { client_error(context, "Could not receive replication data: %s", PQerrorMessage(context->repl.conn)); return EIO; } if (context->sql_conn && !PQconsumeInput(context->sql_conn)) { client_error(context, "Could not receive snapshot data: %s", PQerrorMessage(context->sql_conn)); return EIO; } return 0; }
static void init_slot(ParallelSlot *slot, PGconn *conn, const char *progname) { slot->connection = conn; slot->isFree = true; slot->sock = PQsocket(conn); if (slot->sock < 0) { fprintf(stderr, _("%s: invalid socket: %s"), progname, PQerrorMessage(conn)); exit(1); } }
static void evpg_make_evquery(int sock, short which, void **data) { struct evpg_db_node *dbnode; struct evpg_cfg *config; const char *querystr; void (*cb)(PGresult *, void *); void *usrdata; struct event *event; config = data[0]; querystr = data[1]; cb = data[2]; usrdata = data[3]; dbnode = data[4]; event = data[5]; if (!dbnode) { if (!(dbnode = evpg_snatch_connection(config))) { event_set(event, 0, EV_WRITE, (void *)evpg_make_evquery, data); event_add(event, 0); return; } } PQsendQuery(dbnode->dbconn, querystr); if (PQstatus(dbnode->dbconn) != CONNECTION_OK) { cb(NULL, usrdata); evpg_set_ready(config, dbnode); free(event); free(data); } data[4] = dbnode; evpg_set_active(config, dbnode); event_set(&dbnode->event, PQsocket(dbnode->dbconn), EV_WRITE, (void *)evpg_query_finished, data); event_add(&dbnode->event, 0); }
static PGresult* wait_for_result(PlxFn *plx_fn, PlxConn *plx_conn) { struct epoll_event listenev; struct epoll_event event; PGconn *pq_conn = plx_conn->pq_conn; PGresult *pg_result = NULL; listenev.events = EPOLLIN; listenev.data.fd = PQsocket(pq_conn); if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listenev.data.fd, &listenev) < 0) plx_error(plx_fn, "epoll: socket adding failed"); PG_TRY(); { int tmp; while ((tmp = is_pq_busy(pq_conn))) { if (tmp == -1) { epoll_ctl(epoll_fd, EPOLL_CTL_DEL, listenev.data.fd, &listenev); plx_error(plx_fn, "%s", PQerrorMessage(pq_conn)); } CHECK_FOR_INTERRUPTS(); epoll_wait(epoll_fd, &event, 1, 10000); } } PG_CATCH(); { epoll_ctl(epoll_fd, EPOLL_CTL_DEL, listenev.data.fd, &listenev); if (geterrcode() == ERRCODE_QUERY_CANCELED) PQrequestCancel(pq_conn); pg_result = PQgetResult(pq_conn); if (pg_result) PQclear(pg_result); PG_RE_THROW(); } PG_END_TRY(); epoll_ctl(epoll_fd, EPOLL_CTL_DEL, listenev.data.fd, &listenev); return PQgetResult(pq_conn); }
int sql_init ( dbref player, dbref cause, char *buff, char **bufc ) { PGconn *pgsql; PGresult *result; char connect_string[CONNECT_STRING_SIZE]; /* * Make sure we have valid config options. */ if ( !mod_db_sql_config.host || !*mod_db_sql_config.host ) return -1; if ( !mod_db_sql_config.db || !*mod_db_sql_config.db ) return -1; /* * If we are already connected, drop and retry the connection, in * case for some reason the server went away. */ if ( pgsql_struct ) sql_shutdown ( 0, 0, NULL, NULL ); /* * Try to connect to the database host. If we have specified * localhost, use the Unix domain socket instead. */ snprintf ( connect_string, CONNECT_STRING_SIZE, "host = '%s' dbname = '%s' user = '******' password = '******'", mod_db_sql_config.host, mod_db_sql_config.db, mod_db_sql_config.username, mod_db_sql_config.password ); pgsql = PQconnectdb ( connect_string ); if ( !pgsql ) { log_write ( LOG_ALWAYS, "SQL", "CONN", "Failed connection to SQL server %s: %s", mod_db_sql_config.host, PQerrorMessage ( pgsql ) ); return -1; } log_write ( LOG_ALWAYS, "SQL", "CONN", "Connected to SQL server %s, SQL database selected: %s", PQhost ( pgsql ), PQdb ( pgsql ) ); pgsql_struct = pgsql; mod_db_sql_config.socket = PQsocket ( pgsql ); return 1; }
static int do_connect(const char *s, our_data_t* data) { ei_x_buff x; PGconn* conn = PQconnectdb(s); ei_x_new_with_version(&x); if (PQstatus(conn) != CONNECTION_OK) { encode_error(&x, conn); PQfinish(conn); conn = NULL; } else { encode_ok(&x); data->socket = PQsocket(conn); driver_select(data->port, (ErlDrvEvent)data->socket, DO_READ, 1); } driver_output(data->port, x.buff, x.index); ei_x_free(&x); data->conn = conn; return 0; }
char *pl_read(PGconn *conn) { // Sleep until something happens on the connection. We use select(2) //to wait for input, but you could also use poll() or similar // facilities. int sock; fd_set input_mask; PGnotify *notify; char *not_name; sock = PQsocket(conn); if (sock < 0) { fprintf(stderr, "shouldn't happen: sock < 0"); exit_nicely(conn); } FD_ZERO(&input_mask); FD_SET(sock, &input_mask); try_again: if (select(sock + 1, &input_mask, NULL, NULL, NULL) < 0) { fprintf(stderr, "select() failed: %s\n", strerror(errno)); exit_nicely(conn); } // Now check for input PQconsumeInput(conn); if ((notify = PQnotifies(conn)) != NULL) { fprintf(stderr, "ASYNC NOTIFY of '%s' received from backend pid %d\n", notify->relname, notify->be_pid); not_name = (char *)malloc((strlen(notify->relname) + 1) * sizeof(char)); strcpy(not_name, notify->relname); PQfreemem(notify); return not_name; } else { goto try_again; } }
void PGDatabase::GetNotify(pgdb_monitor_callback pmc, void* param) { PGnotify *notify; struct pgdb_monitor_result pmr; while (true) { /* * Sleep until something happens on the connection. We use select(2) * to wait for input, but you could also use poll() or similar * facilities. */ int sock; fd_set input_mask; sock = PQsocket(m_pConnect); if (sock < 0) break; /* shouldn't happen */ FD_ZERO(&input_mask); FD_SET(sock, &input_mask); if (select(sock + 1, &input_mask, NULL, NULL, NULL) < 0) { fprintf(stderr, "select() failed: %s\n", strerror(errno)); } /* Now check for input */ PQconsumeInput(m_pConnect); while ((notify = PQnotifies(m_pConnect)) != NULL) { memset(pmr.tablename, 0 , MAXTABLENAMELEN); memset(pmr.opvalues, 0 , MAXOPVALUELEN); memcpy(pmr.tablename, notify->relname, strlen(notify->relname)); memcpy(pmr.opvalues, notify->extra, strlen(notify->extra)); pmc(&pmr,param); PQfreemem(notify); } } }
/* * Wait for the result from a prior asynchronous execution function call. * * This function offers quick responsiveness by checking for any interruptions. * * This function emulates the PQexec()'s behavior of returning the last result * when there are many. * * Caller is responsible for the error handling on the result. */ PGresult * pgfdw_get_result(PGconn *conn, const char *query) { PGresult *last_res = NULL; for (;;) { PGresult *res; while (PQisBusy(conn)) { int wc; /* Sleep until there's something to do */ wc = WaitLatchOrSocket(MyLatch, WL_LATCH_SET | WL_SOCKET_READABLE, PQsocket(conn), -1L, PG_WAIT_EXTENSION); ResetLatch(MyLatch); CHECK_FOR_INTERRUPTS(); /* Data available in socket */ if (wc & WL_SOCKET_READABLE) { if (!PQconsumeInput(conn)) pgfdw_report_error(ERROR, NULL, conn, false, query); } } res = PQgetResult(conn); if (res == NULL) break; /* query is complete */ PQclear(last_res); last_res = res; } return last_res; }
LispObj * Lisp_PQsocket(LispBuiltin *builtin) /* pq-socket connection */ { int sock; PGconn *conn; LispObj *connection; connection = ARGUMENT(0); if (!CHECKO(connection, PGconn_t)) LispDestroy("%s: cannot convert %s to PGconn*", STRFUN(builtin), STROBJ(connection)); conn = (PGconn*)(connection->data.opaque.data); sock = PQsocket(conn); return (INTEGER(sock)); }
/* * Our caller already sent the query associated with this step. Wait for it * to either complete or (if given the STEP_NONBLOCK flag) to block while * waiting for a lock. We assume that any lock wait will persist until we * have executed additional steps in the permutation. * * When calling this function on behalf of a given step for a second or later * time, pass the STEP_RETRY flag. This only affects the messages printed. * * If the connection returns an error, the message is saved in step->errormsg. * Caller should call report_error_message shortly after this, to have it * printed and cleared. * * If the STEP_NONBLOCK flag was specified and the query is waiting to acquire * a lock, returns true. Otherwise, returns false. */ static bool try_complete_step(Step * step, int flags) { PGconn *conn = conns[1 + step->session]; fd_set read_set; struct timeval timeout; int sock = PQsocket(conn); int ret; PGresult *res; FD_ZERO(&read_set); while ((flags & STEP_NONBLOCK) && PQisBusy(conn)) { FD_SET(sock, &read_set); timeout.tv_sec = 0; timeout.tv_usec = 10000; /* Check for lock waits every 10ms. */ ret = select(sock + 1, &read_set, NULL, NULL, &timeout); if (ret < 0) /* error in select() */ { if (errno == EINTR) continue; fprintf(stderr, "select failed: %s\n", strerror(errno)); exit_nicely(); } else if (ret == 0) /* select() timeout: check for lock wait */ { int ntuples; res = PQexecPrepared(conns[0], PREP_WAITING, 1, &backend_pids[step->session + 1], NULL, NULL, 0); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "lock wait query failed: %s", PQerrorMessage(conn)); exit_nicely(); } ntuples = PQntuples(res); PQclear(res); if (ntuples >= 1) /* waiting to acquire a lock */ { if (!(flags & STEP_RETRY)) printf("step %s: %s <waiting ...>\n", step->name, step->sql); return true; } /* else, not waiting: give it more time */ } else if (!PQconsumeInput(conn)) /* select(): data available */ { fprintf(stderr, "PQconsumeInput failed: %s\n", PQerrorMessage(conn)); exit_nicely(); } } if (flags & STEP_RETRY) printf("step %s: <... completed>\n", step->name); else printf("step %s: %s\n", step->name, step->sql); while ((res = PQgetResult(conn))) { switch (PQresultStatus(res)) { case PGRES_COMMAND_OK: break; case PGRES_TUPLES_OK: printResultSet(res); break; case PGRES_FATAL_ERROR: if (step->errormsg != NULL) { printf("WARNING: this step had a leftover error message\n"); printf("%s\n", step->errormsg); } /* * Detail may contain XID values, so we want to just show * primary. Beware however that libpq-generated error results * may not contain subfields, only an old-style message. */ { const char *sev = PQresultErrorField(res, PG_DIAG_SEVERITY); const char *msg = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY); if (sev && msg) { step->errormsg = malloc(5 + strlen(sev) + strlen(msg)); sprintf(step->errormsg, "%s: %s", sev, msg); } else step->errormsg = strdup(PQresultErrorMessage(res)); } break; default: printf("unexpected result status: %s\n", PQresStatus(PQresultStatus(res))); } PQclear(res); } return false; }
/* * Our caller already sent the query associated with this step. Wait for it * to either complete or (if given the STEP_NONBLOCK flag) to block while * waiting for a lock. We assume that any lock wait will persist until we * have executed additional steps in the permutation. * * When calling this function on behalf of a given step for a second or later * time, pass the STEP_RETRY flag. This only affects the messages printed. * * If the STEP_NONBLOCK flag was specified and the query is waiting to acquire * a lock, returns true. Otherwise, returns false. */ static bool try_complete_step(Step *step, int flags) { PGconn *conn = conns[1 + step->session]; fd_set read_set; struct timeval timeout; int sock = PQsocket(conn); int ret; PGresult *res; FD_ZERO(&read_set); while (flags & STEP_NONBLOCK && PQisBusy(conn)) { FD_SET(sock, &read_set); timeout.tv_sec = 0; timeout.tv_usec = 10000; /* Check for lock waits every 10ms. */ ret = select(sock + 1, &read_set, NULL, NULL, &timeout); if (ret < 0) /* error in select() */ { fprintf(stderr, "select failed: %s\n", strerror(errno)); exit_nicely(); } else if (ret == 0) /* select() timeout: check for lock wait */ { int ntuples; res = PQexecPrepared(conns[0], PREP_WAITING, 1, &backend_pids[step->session + 1], NULL, NULL, 0); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "lock wait query failed: %s", PQerrorMessage(conn)); exit_nicely(); } ntuples = PQntuples(res); PQclear(res); if (ntuples >= 1) /* waiting to acquire a lock */ { if (!(flags & STEP_RETRY)) printf("step %s: %s <waiting ...>\n", step->name, step->sql); return true; } /* else, not waiting: give it more time */ } else if (!PQconsumeInput(conn)) /* select(): data available */ { fprintf(stderr, "PQconsumeInput failed: %s", PQerrorMessage(conn)); exit_nicely(); } } if (flags & STEP_RETRY) printf("step %s: <... completed>\n", step->name); else printf("step %s: %s\n", step->name, step->sql); while ((res = PQgetResult(conn))) { switch (PQresultStatus(res)) { case PGRES_COMMAND_OK: break; case PGRES_TUPLES_OK: printResultSet(res); break; case PGRES_FATAL_ERROR: /* Detail may contain xid values, so just show primary. */ printf("%s: %s\n", PQresultErrorField(res, PG_DIAG_SEVERITY), PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY)); break; default: printf("unexpected result status: %s\n", PQresStatus(PQresultStatus(res))); } PQclear(res); } return false; }
/* * Creates a new gang by logging on a session to each segDB involved. * * call this function in GangContext memory context. * elog ERROR or return a non-NULL gang. */ static Gang* createGang_async(GangType type, int gang_id, int size, int content) { Gang *newGangDefinition; SegmentDatabaseDescriptor *segdbDesc = NULL; int i = 0; int create_gang_retry_counter = 0; int in_recovery_mode_count = 0; int successful_connections = 0; bool retry = false; int poll_timeout = 0; struct timeval startTS; PostgresPollingStatusType *pollingStatus = NULL; /* true means connection status is confirmed, either established or in recovery mode */ bool *connStatusDone = NULL; ELOG_DISPATCHER_DEBUG("createGang type = %d, gang_id = %d, size = %d, content = %d", type, gang_id, size, content); /* check arguments */ Assert(size == 1 || size == getgpsegmentCount()); Assert(CurrentResourceOwner != NULL); Assert(CurrentMemoryContext == GangContext); /* Writer gang is created before reader gangs. */ if (type == GANGTYPE_PRIMARY_WRITER) Insist(!GangsExist()); /* Check writer gang firstly*/ if (type != GANGTYPE_PRIMARY_WRITER && !isPrimaryWriterGangAlive()) ereport(ERROR, (errcode(ERRCODE_GP_INTERCONNECTION_ERROR), errmsg("failed to acquire resources on one or more segments"), errdetail("writer gang got broken before creating reader gangs"))); create_gang_retry: /* If we're in a retry, we may need to reset our initial state, a bit */ newGangDefinition = NULL; successful_connections = 0; in_recovery_mode_count = 0; retry = false; /* allocate and initialize a gang structure */ newGangDefinition = buildGangDefinition(type, gang_id, size, content); Assert(newGangDefinition != NULL); Assert(newGangDefinition->size == size); Assert(newGangDefinition->perGangContext != NULL); MemoryContextSwitchTo(newGangDefinition->perGangContext); /* allocate memory within perGangContext and will be freed automatically when gang is destroyed */ pollingStatus = palloc(sizeof(PostgresPollingStatusType) * size); connStatusDone = palloc(sizeof(bool) * size); struct pollfd *fds; PG_TRY(); { for (i = 0; i < size; i++) { char gpqeid[100]; char *options; /* * Create the connection requests. If we find a segment without a * valid segdb we error out. Also, if this segdb is invalid, we must * fail the connection. */ segdbDesc = &newGangDefinition->db_descriptors[i]; /* * Build the connection string. Writer-ness needs to be processed * early enough now some locks are taken before command line options * are recognized. */ build_gpqeid_param(gpqeid, sizeof(gpqeid), segdbDesc->segindex, type == GANGTYPE_PRIMARY_WRITER, gang_id); options = makeOptions(); /* start connection in asynchronous way */ cdbconn_doConnectStart(segdbDesc, gpqeid, options); if(cdbconn_isBadConnection(segdbDesc)) ereport(ERROR, (errcode(ERRCODE_GP_INTERCONNECTION_ERROR), errmsg("failed to acquire resources on one or more segments"), errdetail("%s (%s)", PQerrorMessage(segdbDesc->conn), segdbDesc->whoami))); connStatusDone[i] = false; /* * If connection status is not CONNECTION_BAD after PQconnectStart(), we must * act as if the PQconnectPoll() had returned PGRES_POLLING_WRITING */ pollingStatus[i] = PGRES_POLLING_WRITING; } /* * Ok, we've now launched all the connection attempts. Start the * timeout clock (= get the start timestamp), and poll until they're * all completed or we reach timeout. */ gettimeofday(&startTS, NULL); fds = (struct pollfd *) palloc0(sizeof(struct pollfd) * size); for(;;) { int nready; int nfds = 0; poll_timeout = getPollTimeout(&startTS); for (i = 0; i < size; i++) { segdbDesc = &newGangDefinition->db_descriptors[i]; /* Skip established connections and in-recovery-mode connections*/ if (connStatusDone[i]) continue; switch (pollingStatus[i]) { case PGRES_POLLING_OK: cdbconn_doConnectComplete(segdbDesc); if (segdbDesc->motionListener == -1 || segdbDesc->motionListener == 0) ereport(ERROR, (errcode(ERRCODE_GP_INTERCONNECTION_ERROR), errmsg("failed to acquire resources on one or more segments"), errdetail("Internal error: No motion listener port (%s)", segdbDesc->whoami))); successful_connections++; connStatusDone[i] = true; continue; case PGRES_POLLING_READING: fds[nfds].fd = PQsocket(segdbDesc->conn); fds[nfds].events = POLLIN; nfds++; break; case PGRES_POLLING_WRITING: fds[nfds].fd = PQsocket(segdbDesc->conn); fds[nfds].events = POLLOUT; nfds++; break; case PGRES_POLLING_FAILED: if (segment_failure_due_to_recovery(&segdbDesc->conn->errorMessage)) { in_recovery_mode_count++; connStatusDone[i] = true; elog(LOG, "segment is in recovery mode (%s)", segdbDesc->whoami); } else { ereport(ERROR, (errcode(ERRCODE_GP_INTERCONNECTION_ERROR), errmsg("failed to acquire resources on one or more segments"), errdetail("%s (%s)", PQerrorMessage(segdbDesc->conn), segdbDesc->whoami))); } break; default: ereport(ERROR, (errcode(ERRCODE_GP_INTERCONNECTION_ERROR), errmsg("failed to acquire resources on one or more segments"), errdetail("unknow pollstatus (%s)", segdbDesc->whoami))); break; } if (poll_timeout == 0) ereport(ERROR, (errcode(ERRCODE_GP_INTERCONNECTION_ERROR), errmsg("failed to acquire resources on one or more segments"), errdetail("timeout expired\n (%s)", segdbDesc->whoami))); } if (nfds == 0) break; CHECK_FOR_INTERRUPTS(); /* Wait until something happens */ nready = poll(fds, nfds, poll_timeout); if (nready < 0) { int sock_errno = SOCK_ERRNO; if (sock_errno == EINTR) continue; ereport(ERROR, (errcode(ERRCODE_GP_INTERCONNECTION_ERROR), errmsg("failed to acquire resources on one or more segments"), errdetail("poll() failed: errno = %d", sock_errno))); } else if (nready > 0) { int currentFdNumber = 0; for (i = 0; i < size; i++) { segdbDesc = &newGangDefinition->db_descriptors[i]; if (connStatusDone[i]) continue; Assert(PQsocket(segdbDesc->conn) > 0); Assert(PQsocket(segdbDesc->conn) == fds[currentFdNumber].fd); if (fds[currentFdNumber].revents & fds[currentFdNumber].events) pollingStatus[i] = PQconnectPoll(segdbDesc->conn); currentFdNumber++; } } } ELOG_DISPATCHER_DEBUG("createGang: %d processes requested; %d successful connections %d in recovery", size, successful_connections, in_recovery_mode_count); MemoryContextSwitchTo(GangContext); /* some segments are in recovery mode*/ if (successful_connections != size) { Assert(successful_connections + in_recovery_mode_count == size); /* FTS shows some segment DBs are down */ if (isFTSEnabled() && FtsTestSegmentDBIsDown(newGangDefinition->db_descriptors, size)) ereport(ERROR, (errcode(ERRCODE_GP_INTERCONNECTION_ERROR), errmsg("failed to acquire resources on one or more segments"), errdetail("FTS detected one or more segments are down"))); if ( gp_gang_creation_retry_count <= 0 || create_gang_retry_counter++ >= gp_gang_creation_retry_count || type != GANGTYPE_PRIMARY_WRITER) ereport(ERROR, (errcode(ERRCODE_GP_INTERCONNECTION_ERROR), errmsg("failed to acquire resources on one or more segments"), errdetail("segments is in recovery mode"))); ELOG_DISPATCHER_DEBUG("createGang: gang creation failed, but retryable."); DisconnectAndDestroyGang(newGangDefinition); newGangDefinition = NULL; retry = true; } } PG_CATCH(); { MemoryContextSwitchTo(GangContext); DisconnectAndDestroyGang(newGangDefinition); newGangDefinition = NULL; if (type == GANGTYPE_PRIMARY_WRITER) { DisconnectAndDestroyAllGangs(true); CheckForResetSession(); } PG_RE_THROW(); } PG_END_TRY(); if (retry) { CHECK_FOR_INTERRUPTS(); pg_usleep(gp_gang_creation_retry_timer * 1000); CHECK_FOR_INTERRUPTS(); goto create_gang_retry; } setLargestGangsize(size); return newGangDefinition; }
int execute_product_detail(struct db_context_t *dbc, struct product_detail_t *data) { char sql_cmd[512]; PGresult *res; int j; /* Create SQL Command */ memset(sql_cmd, 0x00, sizeof(sql_cmd)); sprintf(sql_cmd,STMT_PRODUCT_DETAIL, data->i_id); /* Execute SQL Command */ res = PQexec(dbc->conn, sql_cmd); if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) { LOG_ERROR_MESSAGE("%s\nPQbackendPID[%d]\nPQstatus[%d]\nPQtransactionStatus[%d]\nPQsocket[%d]\nPQprotocolVersion[%d]\n", PQerrorMessage(dbc->conn), PQbackendPID(dbc->conn), (int)PQstatus(dbc->conn), (int)PQtransactionStatus(dbc->conn), PQsocket(dbc->conn), PQprotocolVersion(dbc->conn)); PQclear(res); return ERROR; } if (PQntuples(res) == 0) { LOG_ERROR_MESSAGE("%s\nPQbackendPID[%d]\nPQstatus[%d]\nPQtransactionStatus[%d]\nPQsocket[%d]\nPQprotocolVersion[%d]\n", PQerrorMessage(dbc->conn), PQbackendPID(dbc->conn), (int)PQstatus(dbc->conn), (int)PQtransactionStatus(dbc->conn), PQsocket(dbc->conn), PQprotocolVersion(dbc->conn)); LOG_ERROR_MESSAGE("Could not obtain produce detail\n"); PQclear(res); return ERROR; } /* Get data */ j = 0; strcpy(data->i_title, PQgetvalue(res, 0, j++)); strcpy(data->a_fname, PQgetvalue(res, 0, j++)); strcpy(data->a_lname, PQgetvalue(res, 0, j++)); strcpy(data->i_pub_date, PQgetvalue(res, 0, j++)); strcpy(data->i_publisher, PQgetvalue(res, 0, j++)); strcpy(data->i_subject, PQgetvalue(res, 0, j++)); strcpy(data->i_desc, PQgetvalue(res, 0, j++)); data->i_image = atoll(PQgetvalue(res, 0, j++)); data->i_cost = strtod(PQgetvalue(res, 0, j++), NULL); data->i_srp = strtod(PQgetvalue(res, 0, j++), NULL); strcpy(data->i_avail, PQgetvalue(res, 0, j++)); strcpy(data->i_isbn, PQgetvalue(res, 0, j++)); data->i_page = atoi(PQgetvalue(res, 0, j++)); strcpy(data->i_backing, PQgetvalue(res, 0, j++)); strcpy(data->i_dimensions, PQgetvalue(res, 0, j++)); PQclear(res); return OK; }