📄 fe-connect.c
字号:
/*------------------------------------------------------------------------- * * fe-connect.c * functions related to setting up a connection to the backend * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.98 1999/06/17 15:16:04 momjian Exp $ * *------------------------------------------------------------------------- */#include "libpq-fe.h"#include "libpq-int.h"#include "fe-auth.h"#include "postgres.h"#include <stdlib.h>#ifdef WIN32#include "win32.h"#else#if !defined(NO_UNISTD_H)#include <unistd.h>#endif#include <netdb.h>#include <netinet/tcp.h>#endif#include <fcntl.h>#include <string.h>#include <errno.h>#include <ctype.h> /* for isspace() */#ifndef HAVE_STRDUP#include "strdup.h"#endif#ifdef HAVE_CRYPT_H#include <crypt.h>#endif#ifdef MULTIBYTE#include "mb/pg_wchar.h"#endifstatic ConnStatusType connectDB(PGconn *conn);static PGconn *makeEmptyPGconn(void);static void freePGconn(PGconn *conn);static void closePGconn(PGconn *conn);static int conninfo_parse(const char *conninfo, char *errorMessage);static char *conninfo_getval(char *keyword);static void conninfo_free(void);static void defaultNoticeProcessor(void *arg, const char *message);/* XXX Why is this not static? */void PQsetenv(PGconn *conn);#define NOTIFYLIST_INITIAL_SIZE 10#define NOTIFYLIST_GROWBY 10/* ---------- * Definition of the conninfo parameters and their fallback resources. * If Environment-Var and Compiled-in are specified as NULL, no * fallback is available. If after all no value can be determined * for an option, an error is returned. * * The values for dbname and user are treated special in conninfo_parse. * If the Compiled-in resource is specified as a NULL value, the * user is determined by fe_getauthname() and for dbname the user * name is copied. * * The Label and Disp-Char entries are provided for applications that * want to use PQconndefaults() to create a generic database connection * dialog. Disp-Char is defined as follows: * "" Normal input field * ---------- */static PQconninfoOption PQconninfoOptions[] = {/* ----------------------------------------------------------------- *//* Option-name Environment-Var Compiled-in Current value *//* Label Disp-Char *//* ----------------- --------------- --------------- --------------- */ /* "authtype" is ignored as it is no longer used. */ {"authtype", "PGAUTHTYPE", DefaultAuthtype, NULL, "Database-Authtype", "", 20}, {"user", "PGUSER", NULL, NULL, "Database-User", "", 20}, {"password", "PGPASSWORD", DefaultPassword, NULL, "Database-Password", "", 20}, {"dbname", "PGDATABASE", NULL, NULL, "Database-Name", "", 20}, {"host", "PGHOST", NULL, NULL, "Database-Host", "", 40}, {"port", "PGPORT", DEF_PGPORT, NULL, "Database-Port", "", 6}, {"tty", "PGTTY", DefaultTty, NULL, "Backend-Debug-TTY", "D", 40}, {"options", "PGOPTIONS", DefaultOption, NULL, "Backend-Debug-Options", "D", 40},/* ----------------- --------------- --------------- --------------- */ {NULL, NULL, NULL, NULL, NULL, NULL, 0}};static struct EnvironmentOptions{ const char *envName, *pgName;} EnvironmentOptions[] ={ /* common user-interface settings */ { "PGDATESTYLE", "datestyle" }, { "PGTZ", "timezone" },#ifdef MULTIBYTE { "PGCLIENTENCODING", "client_encoding" },#endif /* internal performance-related settings */ { "PGCOSTHEAP", "cost_heap" }, { "PGCOSTINDEX", "cost_index" }, { "PGGEQO", "geqo" }, { NULL }};/* ---------------- * PQconnectdb * * establishes a connection to a postgres backend through the postmaster * using connection information in a string. * * The conninfo string is a list of * * option = value * * definitions. Value might be a single value containing no whitespaces * or a single quoted string. If a single quote should appear everywhere * in the value, it must be escaped with a backslash like \' * * Returns a PGconn* which is needed for all subsequent libpq calls * if the status field of the connection returned is CONNECTION_BAD, * then some fields may be null'ed out instead of having valid values * ---------------- */PGconn *PQconnectdb(const char *conninfo){ PGconn *conn; char *tmp; /* ---------- * Allocate memory for the conn structure * ---------- */ conn = makeEmptyPGconn(); if (conn == NULL) return (PGconn *) NULL; /* ---------- * Parse the conninfo string and save settings in conn structure * ---------- */ if (conninfo_parse(conninfo, conn->errorMessage) < 0) { conn->status = CONNECTION_BAD; conninfo_free(); return conn; } tmp = conninfo_getval("host"); conn->pghost = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval("port"); conn->pgport = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval("tty"); conn->pgtty = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval("options"); conn->pgoptions = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval("dbname"); conn->dbName = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval("user"); conn->pguser = tmp ? strdup(tmp) : NULL; tmp = conninfo_getval("password"); conn->pgpass = tmp ? strdup(tmp) : NULL; /* ---------- * Free the connection info - all is in conn now * ---------- */ conninfo_free(); /* ---------- * Connect to the database * ---------- */ conn->status = connectDB(conn); return conn;}/* ---------------- * PQconndefaults * * Parse an empty string like PQconnectdb() would do and return the * address of the connection options structure. Using this function * an application might determine all possible options and their * current default values. * ---------------- */PQconninfoOption *PQconndefaults(void){ char errorMessage[ERROR_MSG_LENGTH]; conninfo_parse("", errorMessage); return PQconninfoOptions;}/* ---------------- * PQsetdbLogin * * establishes a connection to a postgres backend through the postmaster * at the specified host and port. * * returns a PGconn* which is needed for all subsequent libpq calls * if the status field of the connection returned is CONNECTION_BAD, * then some fields may be null'ed out instead of having valid values * * Uses these environment variables: * * PGHOST identifies host to which to connect if <pghost> argument * is NULL or a null string. * * PGPORT identifies TCP port to which to connect if <pgport> argument * is NULL or a null string. * * PGTTY identifies tty to which to send messages if <pgtty> argument * is NULL or a null string. * * PGOPTIONS identifies connection options if <pgoptions> argument is * NULL or a null string. * * PGUSER Postgres username to associate with the connection. * * PGPASSWORD The user's password. * * PGDATABASE name of database to which to connect if <pgdatabase> * argument is NULL or a null string * * None of the above need be defined. There are defaults for all of them. * * To support "delimited identifiers" for database names, only convert * the database name to lower case if it is not surrounded by double quotes. * Otherwise, strip the double quotes but leave the reset of the string intact. * - thomas 1997-11-08 * * ---------------- */PGconn *PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, const char *pgtty, const char *dbName, const char *login, const char *pwd){ PGconn *conn; char *tmp; /* An error message from some service we call. */ bool error = FALSE; /* We encountered an error that prevents successful completion */ int i; conn = makeEmptyPGconn(); if (conn == NULL) return (PGconn *) NULL; if ((pghost == NULL) || pghost[0] == '\0') { if ((tmp = getenv("PGHOST")) != NULL) conn->pghost = strdup(tmp); } else conn->pghost = strdup(pghost); if ((pgport == NULL) || pgport[0] == '\0') { if ((tmp = getenv("PGPORT")) == NULL) tmp = DEF_PGPORT; conn->pgport = strdup(tmp); } else conn->pgport = strdup(pgport); if ((pgtty == NULL) || pgtty[0] == '\0') { if ((tmp = getenv("PGTTY")) == NULL) tmp = DefaultTty; conn->pgtty = strdup(tmp); } else conn->pgtty = strdup(pgtty); if ((pgoptions == NULL) || pgoptions[0] == '\0') { if ((tmp = getenv("PGOPTIONS")) == NULL) tmp = DefaultOption; conn->pgoptions = strdup(tmp); } else conn->pgoptions = strdup(pgoptions); if (login) conn->pguser = strdup(login); else if ((tmp = getenv("PGUSER")) != NULL) conn->pguser = strdup(tmp); else conn->pguser = fe_getauthname(conn->errorMessage); if (conn->pguser == NULL) { error = TRUE; sprintf(conn->errorMessage, "FATAL: PQsetdbLogin(): Unable to determine a Postgres username!\n"); } if (pwd) conn->pgpass = strdup(pwd); else if ((tmp = getenv("PGPASSWORD")) != NULL) conn->pgpass = strdup(tmp); else conn->pgpass = strdup(DefaultPassword); if ((dbName == NULL) || dbName[0] == '\0') { if ((tmp = getenv("PGDATABASE")) != NULL) conn->dbName = strdup(tmp); else if (conn->pguser) conn->dbName = strdup(conn->pguser); } else conn->dbName = strdup(dbName); if (conn->dbName) { /* * if the database name is surrounded by double-quotes, then don't * convert case */ if (*conn->dbName == '"') { strcpy(conn->dbName, conn->dbName + 1); conn->dbName[strlen(conn->dbName) - 1] = '\0'; } else for (i = 0; conn->dbName[i]; i++) if (isascii((unsigned char) conn->dbName[i]) && isupper(conn->dbName[i])) conn->dbName[i] = tolower(conn->dbName[i]); } if (error) conn->status = CONNECTION_BAD; else conn->status = connectDB(conn); return conn;}/* * update_db_info - * get all additional infos out of dbName * */static intupdate_db_info(PGconn *conn){ char *tmp, *old = conn->dbName; if (strchr(conn->dbName, '@') != NULL) { /* old style: dbname[@server][:port] */ tmp = strrchr(conn->dbName, ':'); if (tmp != NULL) /* port number given */ { conn->pgport = strdup(tmp + 1); *tmp = '\0'; } tmp = strrchr(conn->dbName, '@'); if (tmp != NULL) /* host name given */ { conn->pghost = strdup(tmp + 1); *tmp = '\0'; } conn->dbName = strdup(old); free(old); } else { int offset; /* * only allow protocols tcp and unix */ if (strncmp(conn->dbName, "tcp:", 4) == 0) offset = 4; else if (strncmp(conn->dbName, "unix:", 5) == 0) offset = 5; else return 0; if (strncmp(conn->dbName + offset, "postgresql://", strlen("postgresql://")) == 0) { /* * new style: * <tcp|unix>:postgresql://server[:port][/dbname][?options] */ offset += strlen("postgresql://"); tmp = strrchr(conn->dbName + offset, '?'); if (tmp != NULL) /* options given */ { conn->pgoptions = strdup(tmp + 1); *tmp = '\0'; } tmp = strrchr(conn->dbName + offset, '/'); if (tmp != NULL) /* database name given */ { conn->dbName = strdup(tmp + 1); *tmp = '\0'; } else { if ((tmp = getenv("PGDATABASE")) != NULL) conn->dbName = strdup(tmp); else if (conn->pguser) conn->dbName = strdup(conn->pguser); } tmp = strrchr(old + offset, ':'); if (tmp != NULL) /* port number given */ { conn->pgport = strdup(tmp + 1); *tmp = '\0'; } if (strncmp(old, "unix:", 5) == 0) { conn->pghost = NULL; if (strcmp(old + offset, "localhost") != 0) { (void) sprintf(conn->errorMessage, "connectDB() -- non-tcp access only possible on localhost\n"); return 1; } } else conn->pghost = strdup(old + offset); free(old); } } return 0;}/* * connectDB - * make a connection to the backend so it is ready to receive queries. * return CONNECTION_OK if successful, CONNECTION_BAD if not. * */static ConnStatusTypeconnectDB(PGconn *conn){ PGresult *res; struct hostent *hp; StartupPacket sp; AuthRequest areq;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -