Пример #1
0
Файл: evpg.c Проект: ellzey/evpg
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);
}
Пример #2
0
	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();
	}
Пример #3
0
static int
_conn_async_connect(connectionObject *self)
{
    PGconn *pgconn;

    self->pgconn = pgconn = PQconnectStart(self->dsn);

    Dprintf("conn_connect: new postgresql connection at %p", pgconn);

    if (pgconn == NULL)
    {
        Dprintf("conn_connect: PQconnectStart(%s) FAILED", self->dsn);
        PyErr_SetString(OperationalError, "PQconnectStart() failed");
        return -1;
    }
    else if (PQstatus(pgconn) == CONNECTION_BAD)
    {
        Dprintf("conn_connect: PQconnectdb(%s) returned BAD", self->dsn);
        PyErr_SetString(OperationalError, PQerrorMessage(pgconn));
        return -1;
    }

    PQsetNoticeProcessor(pgconn, conn_notice_callback, (void*)self);

    /* The connection will be completed banging on poll():
     * First with _conn_poll_connecting() that will finish connection,
     * then with _conn_poll_setup_async() that will do the same job
     * of setup_async(). */

    return 0;
}
Пример #4
0
CAMLprim value PQconnectdb_stub(value v_conn_info, value v_startonly)
{
  PGconn *conn;
  value v_conn;
  PGcancel *cancel;

  if (Bool_val(v_startonly)) {
    conn = PQconnectStart(String_val(v_conn_info));
    cancel = PQgetCancel(conn);
  }
  else {
    size_t len = caml_string_length(v_conn_info) + 1;
    char *conn_info = caml_stat_alloc(len);
    memcpy(conn_info, String_val(v_conn_info), len);
    caml_enter_blocking_section();
      conn = PQconnectdb(conn_info);
      cancel = PQgetCancel(conn);
      free(conn_info);
    caml_leave_blocking_section();
  }

  /* One may raise this 30 to 500 for instance if the program takes
     responsibility of closing connections */
  v_conn = caml_alloc_small(3, Abstract_tag);

  set_conn(v_conn, conn);
  set_conn_cb(v_conn, NULL);
  set_cancel_obj(v_conn, cancel);

  return v_conn;
}
Пример #5
0
static int
_conn_sync_connect(connectionObject *self)
{
    PGconn *pgconn;
    int green;

    /* store this value to prevent inconsistencies due to a change
     * in the middle of the function. */
    green = psyco_green();
    if (!green) {
        Py_BEGIN_ALLOW_THREADS;
        self->pgconn = pgconn = PQconnectdb(self->dsn);
        Py_END_ALLOW_THREADS;
        Dprintf("conn_connect: new postgresql connection at %p", pgconn);
    }
    else {
        Py_BEGIN_ALLOW_THREADS;
        self->pgconn = pgconn = PQconnectStart(self->dsn);
        Py_END_ALLOW_THREADS;
        Dprintf("conn_connect: new green postgresql connection at %p", pgconn);
    }

    if (pgconn == NULL)
    {
        Dprintf("conn_connect: PQconnectdb(%s) FAILED", self->dsn);
        PyErr_SetString(OperationalError, "PQconnectdb() failed");
        return -1;
    }
    else if (PQstatus(pgconn) == CONNECTION_BAD)
    {
        Dprintf("conn_connect: PQconnectdb(%s) returned BAD", self->dsn);
        PyErr_SetString(OperationalError, PQerrorMessage(pgconn));
        return -1;
    }

    PQsetNoticeProcessor(pgconn, conn_notice_callback, (void*)self);

    /* if the connection is green, wait to finish connection */
    if (green) {
        if (0 > pq_set_non_blocking(self, 1)) {
            return -1;
        }
        if (0 != psyco_wait(self)) {
            return -1;
        }
    }

    /* From here the connection is considered ready: with the new status,
     * poll() will use PQisBusy instead of PQconnectPoll.
     */
    self->status = CONN_STATUS_READY;

    if (conn_setup(self, self->pgconn) == -1) {
        return -1;
    }

    return 0;
}
Пример #6
0
/*
 * MultiClientConnectStart asynchronously tries to establish a connection. If it
 * succeeds, it returns the connection id. Otherwise, it reports connection
 * error and returns INVALID_CONNECTION_ID.
 */
int32
MultiClientConnectStart(const char *nodeName, uint32 nodePort, const char *nodeDatabase)
{
	PGconn *connection = NULL;
	char connInfoString[STRING_BUFFER_SIZE];
	ConnStatusType connStatusType = CONNECTION_BAD;
	char *userName = CurrentUserName();

	int32 connectionId = AllocateConnectionId();
	if (connectionId == INVALID_CONNECTION_ID)
	{
		ereport(WARNING, (errmsg("could not allocate connection in connection pool")));
		return connectionId;
	}

	if (XactModificationLevel > XACT_MODIFICATION_NONE)
	{
		ereport(ERROR, (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
						errmsg("cannot open new connections after the first modification "
							   "command within a transaction")));
	}

	/* transcribe connection paremeters to string */
	snprintf(connInfoString, STRING_BUFFER_SIZE, CONN_INFO_TEMPLATE,
			 nodeName, nodePort, nodeDatabase, userName, CLIENT_CONNECT_TIMEOUT);

	/* prepare asynchronous request for worker node connection */
	connection = PQconnectStart(connInfoString);
	connStatusType = PQstatus(connection);

	/*
	 * If prepared, we save the connection, and set its initial polling status
	 * to PGRES_POLLING_WRITING as specified in "Database Connection Control
	 * Functions" section of the PostgreSQL documentation.
	 */
	if (connStatusType != CONNECTION_BAD)
	{
		ClientConnectionArray[connectionId] = connection;
		ClientPollingStatusArray[connectionId] = PGRES_POLLING_WRITING;
	}
	else
	{
		WarnRemoteError(connection, NULL);

		PQfinish(connection);
		connectionId = INVALID_CONNECTION_ID;
	}

	return connectionId;
}
Пример #7
0
static int
esql_postgresql_connect(Esql *e)
{
   e->backend.db = PQconnectStart(e->backend.conn_str);
   free(e->backend.conn_str);
   e->backend.conn_str = NULL;
   e->backend.conn_str_len = 0;
   EINA_SAFETY_ON_NULL_RETURN_VAL(e->backend.db, ECORE_FD_ERROR);
   if (PQstatus(e->backend.db) == CONNECTION_BAD)
     {
        ERR("%s", esql_postgresql_error_get(e));
        return ECORE_FD_ERROR;
     }
   return ECORE_FD_READ | ECORE_FD_WRITE;
}
Пример #8
0
ngx_int_t
ngx_postgres_upstream_get_peer(ngx_peer_connection_t *pc, void *data)
{
    ngx_postgres_upstream_peer_data_t  *pgdt = data;
    ngx_postgres_upstream_srv_conf_t   *pgscf;
#if defined(nginx_version) && (nginx_version < 8017)
    ngx_postgres_ctx_t                 *pgctx;
#endif
    ngx_postgres_upstream_peers_t      *peers;
    ngx_postgres_upstream_peer_t       *peer;
    ngx_connection_t                   *pgxc = NULL;
    int                                 fd;
    ngx_event_t                        *rev, *wev;
    ngx_int_t                           rc;
    u_char                             *connstring, *last;
    size_t                              len;

    dd("entering");

#if defined(nginx_version) && (nginx_version < 8017)
    if (data == NULL) {
        goto failed;
    }

    pgctx = ngx_http_get_module_ctx(pgdt->request, ngx_postgres_module);
#endif

    pgscf = pgdt->srv_conf;

    pgdt->failed = 0;

    if (pgscf->max_cached && pgscf->single) {
        rc = ngx_postgres_keepalive_get_peer_single(pc, pgdt, pgscf);
        if (rc != NGX_DECLINED) {
            /* re-use keepalive peer */
            dd("re-using keepalive peer (single)");

            pgdt->state = state_db_send_query;

            ngx_postgres_process_events(pgdt->request);

            dd("returning NGX_AGAIN");
            return NGX_AGAIN;
        }
    }

    peers = pgscf->peers;

    if (pgscf->current > peers->number - 1) {
        pgscf->current = 0;
    }

    peer = &peers->peer[pgscf->current++];

    pgdt->name.len = peer->name.len;
    pgdt->name.data = peer->name.data;

    pgdt->sockaddr = *peer->sockaddr;

    pc->name = &pgdt->name;
    pc->sockaddr = &pgdt->sockaddr;
    pc->socklen = peer->socklen;
    pc->cached = 0;

    if ((pgscf->max_cached) && (!pgscf->single)) {
        rc = ngx_postgres_keepalive_get_peer_multi(pc, pgdt, pgscf);
        if (rc != NGX_DECLINED) {
            /* re-use keepalive peer */
            dd("re-using keepalive peer (multi)");

            pgdt->state = state_db_send_query;

            ngx_postgres_process_events(pgdt->request);

            dd("returning NGX_AGAIN");
            return NGX_AGAIN;
        }
    }

    if ((pgscf->reject) && (pgscf->active_conns >= pgscf->max_cached)) {
        ngx_log_error(NGX_LOG_INFO, pc->log, 0,
                      "postgres: keepalive connection pool is full,"
                      " rejecting request to upstream \"%V\"", &peer->name);

        /* a bit hack-ish way to return error response (setup part) */
        pc->connection = ngx_get_connection(0, pc->log);

#if defined(nginx_version) && (nginx_version < 8017)
        pgctx->status = NGX_HTTP_SERVICE_UNAVAILABLE;
#endif

        dd("returning NGX_AGAIN (NGX_HTTP_SERVICE_UNAVAILABLE)");
        return NGX_AGAIN;
    }

    /* sizeof("...") - 1 + 1 (for spaces and '\0' omitted */
    len = sizeof("hostaddr=") + peer->host.len
        + sizeof("port=") + sizeof("65535") - 1
        + sizeof("dbname=") + peer->dbname.len
        + sizeof("user="******"password="******"sslmode=disable");

    connstring = ngx_pnalloc(pgdt->request->pool, len);
    if (connstring == NULL) {
#if defined(nginx_version) && (nginx_version >= 8017)
        dd("returning NGX_ERROR");
        return NGX_ERROR;
#else
        goto failed;
#endif
    }

    /* TODO add unix sockets */
    last = ngx_snprintf(connstring, len - 1,
                        "hostaddr=%V port=%d dbname=%V user=%V password=%V"
                        " sslmode=disable",
                        &peer->host, peer->port, &peer->dbname, &peer->user,
                        &peer->password);
    *last = '\0';

    dd("PostgreSQL connection string: %s", connstring);

    /*
     * internal checks in PQsetnonblocking are taking care of any
     * PQconnectStart failures, so we don't need to check them here.
     */

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                   "postgres: connecting");

    pgdt->pgconn = PQconnectStart((const char *)connstring);
    if (PQsetnonblocking(pgdt->pgconn, 1) == -1) {
        ngx_log_error(NGX_LOG_ERR, pc->log, 0,
                      "postgres: connection failed: %s in upstream \"%V\"",
                      PQerrorMessage(pgdt->pgconn), &peer->name);

        PQfinish(pgdt->pgconn);
        pgdt->pgconn = NULL;

#if defined(nginx_version) && (nginx_version >= 8017)
        dd("returning NGX_DECLINED");
        return NGX_DECLINED;
#else
        pgctx->status = NGX_HTTP_BAD_GATEWAY;
        goto failed;
#endif
    }

#if defined(DDEBUG) && (DDEBUG > 1)
    PQtrace(pgdt->pgconn, stderr);
#endif

    dd("connection status:%d", (int) PQstatus(pgdt->pgconn));

    /* take spot in keepalive connection pool */
    pgscf->active_conns++;

    /* add the file descriptor (fd) into an nginx connection structure */

    fd = PQsocket(pgdt->pgconn);
    if (fd == -1) {
        ngx_log_error(NGX_LOG_ERR, pc->log, 0,
                      "postgres: failed to get connection fd");

        goto invalid;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                   "postgres: connection fd:%d", fd);

    pgxc = pc->connection = ngx_get_connection(fd, pc->log);

    if (pgxc == NULL) {
        ngx_log_error(NGX_LOG_ERR, pc->log, 0,
                      "postgres: failed to get a free nginx connection");

        goto invalid;
    }

    pgxc->log = pc->log;
    pgxc->log_error = pc->log_error;
    pgxc->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);

    rev = pgxc->read;
    wev = pgxc->write;

    rev->log = pc->log;
    wev->log = pc->log;

    /* register the connection with postgres connection fd into the
     * nginx event model */

    if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
        dd("NGX_USE_RTSIG_EVENT");
        if (ngx_add_conn(pgxc) != NGX_OK) {
            goto bad_add;
        }

    } else if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
        dd("NGX_USE_CLEAR_EVENT");
        if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT) != NGX_OK) {
            goto bad_add;
        }

        if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_CLEAR_EVENT) != NGX_OK) {
            goto bad_add;
        }

    } else {
        dd("NGX_USE_LEVEL_EVENT");
        if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) != NGX_OK) {
            goto bad_add;
        }

        if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT) != NGX_OK) {
            goto bad_add;
        }
    }

    pgxc->log->action = "connecting to PostgreSQL database";
    pgdt->state = state_db_connect;

    dd("returning NGX_AGAIN");
    return NGX_AGAIN;

bad_add:

    ngx_log_error(NGX_LOG_ERR, pc->log, 0,
                  "postgres: failed to add nginx connection");

invalid:

    ngx_postgres_upstream_free_connection(pc->log, pc->connection,
                                          pgdt->pgconn, pgscf);

#if defined(nginx_version) && (nginx_version >= 8017)
    dd("returning NGX_ERROR");
    return NGX_ERROR;
#else

failed:

    /* a bit hack-ish way to return error response (setup part) */
    pc->connection = ngx_get_connection(0, pc->log);

    dd("returning NGX_AGAIN (NGX_ERROR)");
    return NGX_AGAIN;
#endif
}