Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  connect.c

  Sprache: C
 

/* src/interfaces/ecpg/ecpglib/connect.c */

#define POSTGRES_ECPG_INTERNAL
#include "postgres_fe.h"

#include "ecpg-pthread-win32.h"
#include "ecpgerrno.h"
#include "ecpglib.h"
#include "ecpglib_extern.h"
#include "ecpgtype.h"
#include "sqlca.h"

#ifdef HAVE_USELOCALE
locale_t ecpg_clocale = (locale_t) 0;
#endif

static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_key_t actual_connection_key;
static pthread_once_t actual_connection_key_once = PTHREAD_ONCE_INIT;
static struct connection *actual_connection = NULL;
static struct connection *all_connections = NULL;

static void
ecpg_actual_connection_init(void)
{
 pthread_key_create(&actual_connection_key, NULL);
}

void
ecpg_pthreads_init(void)
{
 pthread_once(&actual_connection_key_once, ecpg_actual_connection_init);
}

static struct connection *
ecpg_get_connection_nr(const char *connection_name)
{
 struct connection *ret = NULL;

 if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
 {
  ecpg_pthreads_init(); /* ensure actual_connection_key is valid */

  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 == NULL)
   /* no TSD connection, going for global */
   ret = actual_connection;
 }
 else
 {
  struct connection *con;

  for (con = all_connections; con != NULL; con = con->next)
  {
   /*
    * Check for the case of a NULL connection name, stored as such in
    * the connection information by ECPGconnect() when the database
    * name is not specified by its caller.
 */

   if (con->name != NULL && strcmp(connection_name, con->name) == 0)
    break;
  }
  ret = con;
 }

 return ret;
}

struct connection *
ecpg_get_connection(const char *connection_name)
{
 struct connection *ret = NULL;

 if ((connection_name == NULL) || (strcmp(connection_name, "CURRENT") == 0))
 {
  ecpg_pthreads_init(); /* ensure actual_connection_key is valid */

  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 == NULL)
   /* no TSD connection here either, using global */
   ret = actual_connection;
 }
 else
 {
  pthread_mutex_lock(&connections_mutex);

  ret = ecpg_get_connection_nr(connection_name);

  pthread_mutex_unlock(&connections_mutex);
 }

 return ret;
}

static void
ecpg_finish(struct connection *act)
{
 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;
  }

  if (pthread_getspecific(actual_connection_key) == act)
   pthread_setspecific(actual_connection_key, all_connections);
  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");
}

bool
ECPGsetcommit(int lineno, const char *mode, const char *connection_name)
{
 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)
{
 struct connection *con = ecpg_get_connection(connection_name);

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

 pthread_setspecific(actual_connection_key, con);
 return true;
}


static void
ECPGnoticeReceiver(void *arg, const PGresult *result)
{
 char    *sqlstate = PQresultErrorField(result, PG_DIAG_SQLSTATE);
 char    *message = PQresultErrorField(result, PG_DIAG_MESSAGE_PRIMARY);
 struct sqlca_t *sqlca = ECPGget_sqlca();
 int   sqlcode;

 if (sqlca == NULL)
 {
  ecpg_log("out of memory");
  return;
 }

 (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);
}

/* this contains some quick hacks, needs to be cleaned up, but it works */
bool
ECPGconnect(int lineno, int c, const char *name, const char *user, const char *passwd, const char *connection_name, int autocommit)
{
 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;

 if (sqlca == NULL)
 {
  ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
       ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
  ecpg_free(dbname);
  return false;
 }

 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";

 ecpg_pthreads_init();

 /* 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)
 {
  ecpg_free(dbname);
  return false;
 }

 if (dbname != NULL)
 {
  /* get the detail information from 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][/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 given */
    {
     *tmp = '\0';
     port = ecpg_strdup(tmp + 1, lineno);
     connect_params++;
    }

    if (strncmp(dbname, "unix:"5) == 0)
    {
     /*
      * The alternative of using "127.0.0.1" here is deprecated
      * and undocumented; we'll keep it for backward
      * compatibility's sake, but not extend it to allow IPv6.
 */

     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
    {
     if (*(dbname + offset) != '\0')
     {
      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;

 /*
  * Count options for the allocation done below (this may produce an
  * overestimate, it's ok).
 */

 if (options)
  for (i = 0; options[i]; i++)
   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.  These allocations
  * are done before manipulating the list of connections to ease the error
  * handling on failure.
 */

 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;
 }

 /* add connection to our list */
 pthread_mutex_lock(&connections_mutex);

 /*
  * ... but first, make certain we have created ecpg_clocale.  Rely on
  * holding connections_mutex to ensure this is done by only one thread.
 */

#ifdef HAVE_USELOCALE
 if (!ecpg_clocale)
 {
  ecpg_clocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
  if (!ecpg_clocale)
  {
   pthread_mutex_unlock(&connections_mutex);
   ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
        ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, 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;
  }
 }
#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;
 pthread_setspecific(actual_connection_key, all_connections);
 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 : "");

 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;

  /*
   * The options string contains "keyword=value" pairs separated by
   * '&'s.  We must break this up into keywords and values to pass to
   * libpq (it's okay to scribble on the options string).  We ignore
   * spaces just before each keyword or value.  (The preprocessor used
   * to add spaces around '&'s, making it necessary to ignore spaces
   * before keywords here.  While it no longer does that, we still must
   * skip spaces to support code compiled with older preprocessors.)
 */

  for (str = options; *str;)
  {
   int   e,
      a;
   char    *token1,
        *token2;

   /* Skip spaces before keyword */
   for (token1 = str; *token1 == ' '; token1++)
     /* skip */ ;
   /* Find end of keyword */
   for (e = 0; token1[e] && token1[e] != '='; e++)
     /* skip */ ;
   if (token1[e])  /* found "=" */
   {
    token1[e] = '\0';
    /* Skip spaces before value */
    for (token2 = token1 + e + 1; *token2 == ' '; token2++)
      /* skip */ ;
    /* Find end of value */
    for (a = 0; token2[a] && token2[a] != '&'; a++)
      /* skip */ ;
    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
   {
    /* Bogus options syntax ... ignore trailing garbage */
    str = token1 + e;
   }
  }
 }

 Assert(i <= connect_params);
 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>");

  /* PQerrorMessage's result already has a trailing newline */
  ecpg_log("ECPGconnect: %s", errmsg);

  ecpg_finish(this);
  pthread_mutex_unlock(&connections_mutex);

  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);

 pthread_mutex_unlock(&connections_mutex);

 this->autocommit = autocommit;

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

 return true;
}

bool
ECPGdisconnect(int lineno, const char *connection_name)
{
 struct sqlca_t *sqlca = ECPGget_sqlca();
 struct connection *con;

 if (sqlca == NULL)
 {
  ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
       ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
  return false;
 }

 pthread_mutex_lock(&connections_mutex);

 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))
  {
   pthread_mutex_unlock(&connections_mutex);
   return false;
  }
  else
   ecpg_finish(con);
 }

 pthread_mutex_unlock(&connections_mutex);

 return true;
}

PGconn *
ECPGget_PGconn(const char *connection_name)
{
 struct connection *con;

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

 return con->connection;
}

Messung V0.5 in Prozent
C=94 H=93 G=93

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002