Header And Logo

PostgreSQL
| The world's most advanced open source database.

Defines | Functions | Variables

connect.c File Reference

#include "postgres_fe.h"
#include "ecpg-pthread-win32.h"
#include "ecpgtype.h"
#include "ecpglib.h"
#include "ecpgerrno.h"
#include "extern.h"
#include "sqlca.h"
Include dependency graph for connect.c:

Go to the source code of this file.

Defines

#define POSTGRES_ECPG_INTERNAL

Functions

static struct connectionecpg_get_connection_nr (const char *connection_name)
struct connectionecpg_get_connection (const char *connection_name)
static void ecpg_finish (struct connection *act)
bool ECPGsetcommit (int lineno, const char *mode, const char *connection_name)
bool ECPGsetconn (int lineno, const char *connection_name)
static void ECPGnoticeReceiver (void *arg, const PGresult *result)
bool ECPGconnect (int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
bool ECPGdisconnect (int lineno, const char *connection_name)
PGconnECPGget_PGconn (const char *connection_name)

Variables

static struct connectionactual_connection = NULL
static struct connectionall_connections = NULL

Define Documentation

#define POSTGRES_ECPG_INTERNAL

Definition at line 3 of file connect.c.


Function Documentation

static void ecpg_finish ( struct connection act  )  [static]

Definition at line 113 of file connect.c.

References connection::cache_head, connection::connection, ECPG_COMPAT_PGSQL, ecpg_deallocate_all_conn(), ecpg_free(), ecpg_log(), ivlist, connection::name, var_list::next, ECPGtype_information_cache::next, connection::next, NULL, PQfinish(), pthread_getspecific(), and pthread_setspecific().

Referenced by ECPGconnect(), and ECPGdisconnect().

{
    if (act != NULL)
    {
        struct ECPGtype_information_cache *cache,
                   *ptr;

        ecpg_deallocate_all_conn(0, ECPG_COMPAT_PGSQL, act);
        PQfinish(act->connection);

        /*
         * no need to lock connections_mutex - we're always called by
         * ECPGdisconnect or ECPGconnect, which are holding the lock
         */

        /* remove act from the list */
        if (act == all_connections)
            all_connections = act->next;
        else
        {
            struct connection *con;

            for (con = all_connections; con->next && con->next != act; con = con->next);
            if (con->next)
                con->next = act->next;
        }

#ifdef ENABLE_THREAD_SAFETY
        if (pthread_getspecific(actual_connection_key) == act)
            pthread_setspecific(actual_connection_key, all_connections);
#endif
        if (actual_connection == act)
            actual_connection = all_connections;

        ecpg_log("ecpg_finish: connection %s closed\n", act->name ? act->name : "(null)");

        for (cache = act->cache_head; cache; ptr = cache, cache = cache->next, ecpg_free(ptr));
        ecpg_free(act->name);
        ecpg_free(act);
        /* delete cursor variables when last connection gets closed */
        if (all_connections == NULL)
        {
            struct var_list *iv_ptr;

            for (; ivlist; iv_ptr = ivlist, ivlist = ivlist->next, ecpg_free(iv_ptr));
        }
    }
    else
        ecpg_log("ecpg_finish: called an extra time\n");
}

struct connection* ecpg_get_connection ( const char *  connection_name  )  [read]

Definition at line 74 of file connect.c.

References ecpg_get_connection_nr(), NULL, pthread_getspecific(), pthread_mutex_lock(), and pthread_mutex_unlock().

Referenced by ecpg_auto_prepare(), ecpg_freeStmtCacheEntry(), ECPGconnect(), ECPGdeallocate(), ECPGdeallocate_all(), ECPGdescribe(), ECPGdo(), ECPGget_desc(), ECPGget_PGconn(), ECPGprepare(), ECPGprepared_statement(), ECPGsetcommit(), ECPGsetconn(), ECPGstatus(), ECPGtrans(), and ECPGtransactionStatus().

{
    struct connection *ret = NULL;

    if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
    {
#ifdef ENABLE_THREAD_SAFETY
        ret = pthread_getspecific(actual_connection_key);

        /*
         * if no connection in TSD for this thread, get the global default
         * connection and hope the user knows what they're doing (i.e. using
         * their own mutex to protect that connection from concurrent accesses
         */
        /* if !ret then  we  got the connection from TSD */
        if (NULL == ret)
            /* no TSD connection here either, using global */
            ret = actual_connection;
#else
        ret = actual_connection;
#endif
    }
    else
    {
#ifdef ENABLE_THREAD_SAFETY
        pthread_mutex_lock(&connections_mutex);
#endif

        ret = ecpg_get_connection_nr(connection_name);

#ifdef ENABLE_THREAD_SAFETY
        pthread_mutex_unlock(&connections_mutex);
#endif
    }

    return (ret);
}

static struct connection* ecpg_get_connection_nr ( const char *  connection_name  )  [static, read]

Definition at line 36 of file connect.c.

References connection::name, connection::next, NULL, and pthread_getspecific().

Referenced by ecpg_get_connection(), and ECPGdisconnect().

{
    struct connection *ret = NULL;

    if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
    {
#ifdef ENABLE_THREAD_SAFETY
        ret = pthread_getspecific(actual_connection_key);

        /*
         * if no connection in TSD for this thread, get the global default
         * connection and hope the user knows what they're doing (i.e. using
         * their own mutex to protect that connection from concurrent accesses
         */
        /* if !ret then  we  got the connection from TSD */
        if (NULL == ret)
            /* no TSD connection, going for global */
            ret = actual_connection;
#else
        ret = actual_connection;
#endif
    }
    else
    {
        struct connection *con;

        for (con = all_connections; con != NULL; con = con->next)
        {
            if (strcmp(connection_name, con->name) == 0)
                break;
        }
        ret = con;
    }

    return (ret);
}

bool ECPGconnect ( int  lineno,
int  c,
const char *  name,
const char *  user,
const char *  passwd,
const char *  connection_name,
int  autocommit 
)

Definition at line 265 of file connect.c.

References connection::cache_head, compat, CONNECTION_BAD, ecpg_alloc(), ecpg_clear_auto_mem(), ECPG_CONNECT, ecpg_finish(), ecpg_free(), ecpg_get_connection(), ecpg_gettext, ecpg_init_sqlca(), ecpg_internal_regression_mode, ecpg_log(), ecpg_raise(), ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, ecpg_strdup(), ECPGget_sqlca(), ECPGnoticeReceiver(), errmsg(), free, i, INFORMIX_MODE, last_dir_separator(), next(), NULL, port, PQconnectdbParams(), PQerrorMessage(), PQsetNoticeReceiver(), PQstatus(), connection::prep_stmts, pthread_mutex_lock(), pthread_mutex_unlock(), pthread_setspecific(), and sqlca.

Referenced by main(), and test().

{
    struct sqlca_t *sqlca = ECPGget_sqlca();
    enum COMPAT_MODE compat = c;
    struct connection *this;
    int         i,
                connect_params = 0;
    char       *dbname = name ? ecpg_strdup(name, lineno) : NULL,
               *host = NULL,
               *tmp,
               *port = NULL,
               *realname = NULL,
               *options = NULL;
    const char **conn_keywords;
    const char **conn_values;

    ecpg_init_sqlca(sqlca);

    /*
     * clear auto_mem structure because some error handling functions might
     * access it
     */
    ecpg_clear_auto_mem();

    if (INFORMIX_MODE(compat))
    {
        char       *envname;

        /*
         * Informix uses an environment variable DBPATH that overrides the
         * connection parameters given here. We do the same with PG_DBPATH as
         * the syntax is different.
         */
        envname = getenv("PG_DBPATH");
        if (envname)
        {
            ecpg_free(dbname);
            dbname = ecpg_strdup(envname, lineno);
        }

    }

    if (dbname == NULL && connection_name == NULL)
        connection_name = "DEFAULT";

#if ENABLE_THREAD_SAFETY
    ecpg_pthreads_init();
#endif

    /* check if the identifier is unique */
    if (ecpg_get_connection(connection_name))
    {
        ecpg_free(dbname);
        ecpg_log("ECPGconnect: connection identifier %s is already in use\n",
                 connection_name);
        return false;
    }

    if ((this = (struct connection *) ecpg_alloc(sizeof(struct connection), lineno)) == NULL)
        return false;

    if (dbname != NULL)
    {
        /* get the detail information out of dbname */
        if (strncmp(dbname, "tcp:", 4) == 0 || strncmp(dbname, "unix:", 5) == 0)
        {
            int         offset = 0;

            /*
             * only allow protocols tcp and unix
             */
            if (strncmp(dbname, "tcp:", 4) == 0)
                offset = 4;
            else if (strncmp(dbname, "unix:", 5) == 0)
                offset = 5;

            if (strncmp(dbname + offset, "postgresql://", strlen("postgresql://")) == 0)
            {

                /*------
                 * new style:
                 *  <tcp|unix>:postgresql://server[:port|:/unixsocket/path:]
                 *  [/db name][?options]
                 *------
                 */
                offset += strlen("postgresql://");

                tmp = strrchr(dbname + offset, '?');
                if (tmp != NULL)    /* options given */
                {
                    options = ecpg_strdup(tmp + 1, lineno);
                    *tmp = '\0';
                }

                tmp = last_dir_separator(dbname + offset);
                if (tmp != NULL)    /* database name given */
                {
                    if (tmp[1] != '\0') /* non-empty database name */
                    {
                        realname = ecpg_strdup(tmp + 1, lineno);
                        connect_params++;
                    }
                    *tmp = '\0';
                }

                tmp = strrchr(dbname + offset, ':');
                if (tmp != NULL)    /* port number or Unix socket path given */
                {
                    char       *tmp2;

                    *tmp = '\0';
                    if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
                    {
                        *tmp2 = '\0';
                        host = ecpg_strdup(tmp + 1, lineno);
                        connect_params++;
                        if (strncmp(dbname, "unix:", 5) != 0)
                        {
                            ecpg_log("ECPGconnect: socketname %s given for TCP connection on line %d\n", host, lineno);
                            ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>"));
                            if (host)
                                ecpg_free(host);

                            /*
                             * port not set yet if (port) ecpg_free(port);
                             */
                            if (options)
                                ecpg_free(options);
                            if (realname)
                                ecpg_free(realname);
                            if (dbname)
                                ecpg_free(dbname);
                            free(this);
                            return false;
                        }
                    }
                    else
                    {
                        port = ecpg_strdup(tmp + 1, lineno);
                        connect_params++;
                    }
                }

                if (strncmp(dbname, "unix:", 5) == 0)
                {
                    if (strcmp(dbname + offset, "localhost") != 0 && strcmp(dbname + offset, "127.0.0.1") != 0)
                    {
                        ecpg_log("ECPGconnect: non-localhost access via sockets on line %d\n", lineno);
                        ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>"));
                        if (host)
                            ecpg_free(host);
                        if (port)
                            ecpg_free(port);
                        if (options)
                            ecpg_free(options);
                        if (realname)
                            ecpg_free(realname);
                        if (dbname)
                            ecpg_free(dbname);
                        free(this);
                        return false;
                    }
                }
                else
                {
                    host = ecpg_strdup(dbname + offset, lineno);
                    connect_params++;
                }

            }
        }
        else
        {
            /* old style: dbname[@server][:port] */
            tmp = strrchr(dbname, ':');
            if (tmp != NULL)    /* port number given */
            {
                port = ecpg_strdup(tmp + 1, lineno);
                connect_params++;
                *tmp = '\0';
            }

            tmp = strrchr(dbname, '@');
            if (tmp != NULL)    /* host name given */
            {
                host = ecpg_strdup(tmp + 1, lineno);
                connect_params++;
                *tmp = '\0';
            }

            if (strlen(dbname) > 0)
            {
                realname = ecpg_strdup(dbname, lineno);
                connect_params++;
            }
            else
                realname = NULL;
        }
    }
    else
        realname = NULL;

    /* add connection to our list */
#ifdef ENABLE_THREAD_SAFETY
    pthread_mutex_lock(&connections_mutex);
#endif
    if (connection_name != NULL)
        this->name = ecpg_strdup(connection_name, lineno);
    else
        this->name = ecpg_strdup(realname, lineno);

    this->cache_head = NULL;
    this->prep_stmts = NULL;

    if (all_connections == NULL)
        this->next = NULL;
    else
        this->next = all_connections;

    all_connections = this;
#ifdef ENABLE_THREAD_SAFETY
    pthread_setspecific(actual_connection_key, all_connections);
#endif
    actual_connection = all_connections;

    ecpg_log("ECPGconnect: opening database %s on %s port %s %s%s %s%s\n",
             realname ? realname : "<DEFAULT>",
             host ? host : "<DEFAULT>",
             port ? (ecpg_internal_regression_mode ? "<REGRESSION_PORT>" : port) : "<DEFAULT>",
             options ? "with options " : "", options ? options : "",
             (user && strlen(user) > 0) ? "for user " : "", user ? user : "");

    if (options)
        for (i = 0; options[i]; i++)
            /* count options */
            if (options[i] == '=')
                connect_params++;

    if (user && strlen(user) > 0)
        connect_params++;
    if (passwd && strlen(passwd) > 0)
        connect_params++;

    /* allocate enough space for all connection parameters */
    conn_keywords = (const char **) ecpg_alloc((connect_params + 1) * sizeof(char *), lineno);
    conn_values = (const char **) ecpg_alloc(connect_params * sizeof(char *), lineno);
    if (conn_keywords == NULL || conn_values == NULL)
    {
        if (host)
            ecpg_free(host);
        if (port)
            ecpg_free(port);
        if (options)
            ecpg_free(options);
        if (realname)
            ecpg_free(realname);
        if (dbname)
            ecpg_free(dbname);
        if (conn_keywords)
            ecpg_free(conn_keywords);
        if (conn_values)
            ecpg_free(conn_values);
        free(this);
        return false;
    }

    i = 0;
    if (realname)
    {
        conn_keywords[i] = "dbname";
        conn_values[i] = realname;
        i++;
    }
    if (host)
    {
        conn_keywords[i] = "host";
        conn_values[i] = host;
        i++;
    }
    if (port)
    {
        conn_keywords[i] = "port";
        conn_values[i] = port;
        i++;
    }
    if (user && strlen(user) > 0)
    {
        conn_keywords[i] = "user";
        conn_values[i] = user;
        i++;
    }
    if (passwd && strlen(passwd) > 0)
    {
        conn_keywords[i] = "password";
        conn_values[i] = passwd;
        i++;
    }
    if (options)
    {
        char       *str;

        /* options look like this "option1 = value1 option2 = value2 ... */
        /* we have to break up the string into single options */
        for (str = options; *str;)
        {
            int         e,
                        a;
            char       *token1,
                       *token2;

            for (token1 = str; *token1 && *token1 == ' '; token1++);
            for (e = 0; token1[e] && token1[e] != '='; e++);
            if (token1[e])      /* found "=" */
            {
                token1[e] = '\0';
                for (token2 = token1 + e + 1; *token2 && *token2 == ' '; token2++);
                for (a = 0; token2[a] && token2[a] != '&'; a++);
                if (token2[a])  /* found "&" => another option follows */
                {
                    token2[a] = '\0';
                    str = token2 + a + 1;
                }
                else
                    str = token2 + a;

                conn_keywords[i] = token1;
                conn_values[i] = token2;
                i++;
            }
            else
                /* the parser should not be able to create this invalid option */
                str = token1 + e;
        }

    }
    conn_keywords[i] = NULL;    /* terminator */

    this->connection = PQconnectdbParams(conn_keywords, conn_values, 0);

    if (host)
        ecpg_free(host);
    if (port)
        ecpg_free(port);
    if (options)
        ecpg_free(options);
    if (dbname)
        ecpg_free(dbname);
    ecpg_free(conn_values);
    ecpg_free(conn_keywords);

    if (PQstatus(this->connection) == CONNECTION_BAD)
    {
        const char *errmsg = PQerrorMessage(this->connection);
        const char *db = realname ? realname : ecpg_gettext("<DEFAULT>");

        ecpg_log("ECPGconnect: could not open database: %s\n", errmsg);

        ecpg_finish(this);
#ifdef ENABLE_THREAD_SAFETY
        pthread_mutex_unlock(&connections_mutex);
#endif

        ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db);
        if (realname)
            ecpg_free(realname);

        return false;
    }

    if (realname)
        ecpg_free(realname);

#ifdef ENABLE_THREAD_SAFETY
    pthread_mutex_unlock(&connections_mutex);
#endif

    this->autocommit = autocommit;

    PQsetNoticeReceiver(this->connection, &ECPGnoticeReceiver, (void *) this);

    return true;
}

bool ECPGdisconnect ( int  lineno,
const char *  connection_name 
)

Definition at line 649 of file connect.c.

References ecpg_finish(), ecpg_get_connection_nr(), ecpg_init(), ecpg_init_sqlca(), ECPGget_sqlca(), connection::next, pthread_mutex_lock(), pthread_mutex_unlock(), and sqlca.

Referenced by main(), and test().

{
    struct sqlca_t *sqlca = ECPGget_sqlca();
    struct connection *con;

#ifdef ENABLE_THREAD_SAFETY
    pthread_mutex_lock(&connections_mutex);
#endif

    if (strcmp(connection_name, "ALL") == 0)
    {
        ecpg_init_sqlca(sqlca);
        for (con = all_connections; con;)
        {
            struct connection *f = con;

            con = con->next;
            ecpg_finish(f);
        }
    }
    else
    {
        con = ecpg_get_connection_nr(connection_name);

        if (!ecpg_init(con, connection_name, lineno))
        {
#ifdef ENABLE_THREAD_SAFETY
            pthread_mutex_unlock(&connections_mutex);
#endif
            return (false);
        }
        else
            ecpg_finish(con);
    }

#ifdef ENABLE_THREAD_SAFETY
    pthread_mutex_unlock(&connections_mutex);
#endif

    return true;
}

PGconn* ECPGget_PGconn ( const char *  connection_name  ) 

Definition at line 692 of file connect.c.

References connection::connection, ecpg_get_connection(), and NULL.

{
    struct connection *con;

    con = ecpg_get_connection(connection_name);
    if (con == NULL)
        return NULL;

    return con->connection;
}

static void ECPGnoticeReceiver ( void *  arg,
const PGresult result 
) [static]

Definition at line 219 of file connect.c.

References ecpg_gettext, ecpg_log(), ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION, ECPG_SQLSTATE_DUPLICATE_CURSOR, ECPG_SQLSTATE_INVALID_CURSOR_NAME, ECPG_SQLSTATE_NO_ACTIVE_SQL_TRANSACTION, ECPGget_sqlca(), NULL, PG_DIAG_MESSAGE_PRIMARY, PG_DIAG_SQLSTATE, PQresultErrorField(), sqlca, sqlca_t::sqlcode, sqlca_t::sqlerrm, sqlca_t::sqlerrmc, sqlca_t::sqlerrml, sqlca_t::sqlstate, and sqlca_t::sqlwarn.

Referenced by ECPGconnect().

{
    char       *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
    char       *message = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
    struct sqlca_t *sqlca = ECPGget_sqlca();
    int         sqlcode;

    (void) arg;                 /* keep the compiler quiet */
    if (sqlstate == NULL)
        sqlstate = ECPG_SQLSTATE_ECPG_INTERNAL_ERROR;

    if (message == NULL)        /* Shouldn't happen, but need to be sure */
        message = ecpg_gettext("empty message text");

    /* these are not warnings */
    if (strncmp(sqlstate, "00", 2) == 0)
        return;

    ecpg_log("ECPGnoticeReceiver: %s\n", message);

    /* map to SQLCODE for backward compatibility */
    if (strcmp(sqlstate, ECPG_SQLSTATE_INVALID_CURSOR_NAME) == 0)
        sqlcode = ECPG_WARNING_UNKNOWN_PORTAL;
    else if (strcmp(sqlstate, ECPG_SQLSTATE_ACTIVE_SQL_TRANSACTION) == 0)
        sqlcode = ECPG_WARNING_IN_TRANSACTION;
    else if (strcmp(sqlstate, ECPG_SQLSTATE_NO_ACTIVE_SQL_TRANSACTION) == 0)
        sqlcode = ECPG_WARNING_NO_TRANSACTION;
    else if (strcmp(sqlstate, ECPG_SQLSTATE_DUPLICATE_CURSOR) == 0)
        sqlcode = ECPG_WARNING_PORTAL_EXISTS;
    else
        sqlcode = 0;

    strncpy(sqlca->sqlstate, sqlstate, sizeof(sqlca->sqlstate));
    sqlca->sqlcode = sqlcode;
    sqlca->sqlwarn[2] = 'W';
    sqlca->sqlwarn[0] = 'W';

    strncpy(sqlca->sqlerrm.sqlerrmc, message, sizeof(sqlca->sqlerrm.sqlerrmc));
    sqlca->sqlerrm.sqlerrmc[sizeof(sqlca->sqlerrm.sqlerrmc) - 1] = 0;
    sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);

    ecpg_log("raising sqlcode %d\n", sqlcode);
}

bool ECPGsetcommit ( int  lineno,
const char *  mode,
const char *  connection_name 
)

Definition at line 165 of file connect.c.

References connection::autocommit, connection::connection, ecpg_check_PQresult(), ECPG_COMPAT_PGSQL, ecpg_get_connection(), ecpg_init(), ecpg_log(), connection::name, PQclear(), PQexec(), PQTRANS_IDLE, and PQtransactionStatus().

Referenced by main().

{
    struct connection *con = ecpg_get_connection(connection_name);
    PGresult   *results;

    if (!ecpg_init(con, connection_name, lineno))
        return (false);

    ecpg_log("ECPGsetcommit on line %d: action \"%s\"; connection \"%s\"\n", lineno, mode, con->name);

    if (con->autocommit && strncmp(mode, "off", strlen("off")) == 0)
    {
        if (PQtransactionStatus(con->connection) == PQTRANS_IDLE)
        {
            results = PQexec(con->connection, "begin transaction");
            if (!ecpg_check_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
                return false;
            PQclear(results);
        }
        con->autocommit = false;
    }
    else if (!con->autocommit && strncmp(mode, "on", strlen("on")) == 0)
    {
        if (PQtransactionStatus(con->connection) != PQTRANS_IDLE)
        {
            results = PQexec(con->connection, "commit");
            if (!ecpg_check_PQresult(results, lineno, con->connection, ECPG_COMPAT_PGSQL))
                return false;
            PQclear(results);
        }
        con->autocommit = true;
    }

    return true;
}

bool ECPGsetconn ( int  lineno,
const char *  connection_name 
)

Definition at line 202 of file connect.c.

References ecpg_get_connection(), ecpg_init(), and pthread_setspecific().

Referenced by main().

{
    struct connection *con = ecpg_get_connection(connection_name);

    if (!ecpg_init(con, connection_name, lineno))
        return (false);

#ifdef ENABLE_THREAD_SAFETY
    pthread_setspecific(actual_connection_key, con);
#else
    actual_connection = con;
#endif
    return true;
}


Variable Documentation

struct connection* actual_connection = NULL [static]

Definition at line 18 of file connect.c.

struct connection* all_connections = NULL [static]

Definition at line 19 of file connect.c.