MYSQL* mysql_connect( char *svr_address, char *svr_username, char *svr_password, char *svr_database, int svr_port, bool svr_sa, char *svr_init_command, char *ssl_key, char *ssl_cert, char *ssl_ca, char *ssl_capath, char *ssl_cipher) { MYSQL *conn = NULL; my_bool secure_auth = svr_sa; /* Connect to the server */ conn = _mysql_init(NULL); if (!conn) ereport(ERROR, (errcode(ERRCODE_FDW_OUT_OF_MEMORY), errmsg("failed to initialise the MySQL connection object") )); _mysql_options(conn, MYSQL_SET_CHARSET_NAME, GetDatabaseEncodingName()); _mysql_options(conn, MYSQL_SECURE_AUTH, &secure_auth); if (!svr_sa) elog(WARNING, "MySQL secure authentication is off"); if (svr_init_command != NULL) _mysql_options(conn, MYSQL_INIT_COMMAND, svr_init_command); _mysql_ssl_set(conn, ssl_key, ssl_cert, ssl_ca, ssl_capath, ssl_cipher); if (!_mysql_real_connect(conn, svr_address, svr_username, svr_password, svr_database, svr_port, NULL, 0)) ereport(ERROR, (errcode(ERRCODE_FDW_UNABLE_TO_ESTABLISH_CONNECTION), errmsg("failed to connect to MySQL: %s", _mysql_error(conn)) )); // useful for verifying that the connection's secured elog(DEBUG1, "Successfully connected to MySQL database %s " "at server %s with cipher %s " "(server version: %s, protocol version: %d) ", (svr_database != NULL) ? svr_database : "<none>", _mysql_get_host_info (conn), (ssl_cipher != NULL) ? ssl_cipher : "<none>", _mysql_get_server_info (conn), _mysql_get_proto_info (conn) ); return conn; }
char * PyString_AsString(PyObject *unicode) { char *rv; PyObject *o = PyUnicode_AsEncodedString(unicode, GetDatabaseEncodingName(), NULL); errorCheck(); rv = pstrdup(PyBytes_AsString(o)); Py_XDECREF(o); return rv; }
/* * Get a (python) encoding name for an attribute. */ const char * getPythonEncodingName() { const char *encoding_name = GetDatabaseEncodingName(); if (strcmp(encoding_name, "SQL_ASCII") == 0) { encoding_name = "ascii"; } return encoding_name; }
char * PyUnicode_AsPgString(PyObject *p_unicode) { Py_ssize_t unicode_size = PyUnicode_GET_SIZE(p_unicode); char *message = NULL; PyObject *pTempStr = PyUnicode_Encode(PyUnicode_AsUnicode(p_unicode), unicode_size, GetDatabaseEncodingName(), NULL); errorCheck(); message = strdup(PyBytes_AsString(pTempStr)); errorCheck(); Py_DECREF(pTempStr); return message; }
int PyString_AsStringAndSize(PyObject *obj, char **buffer, Py_ssize_t *length) { PyObject *o; int rv; if (PyUnicode_Check(obj)) { o = PyUnicode_AsEncodedString(obj, GetDatabaseEncodingName(), NULL); errorCheck(); rv = PyBytes_AsStringAndSize(o, buffer, length); Py_XDECREF(o); return rv; } return PyBytes_AsStringAndSize(obj, buffer, length); }
/* * ConnectToNode opens a connection to a remote PostgreSQL server. The function * configures the connection's fallback application name to 'citus' and sets * the remote encoding to match the local one. All parameters are required to * be non NULL. * * We attempt to connect up to MAX_CONNECT_ATTEMPT times. After that we give up * and return NULL. */ PGconn * ConnectToNode(char *nodeName, int32 nodePort, char *nodeUser) { PGconn *connection = NULL; const char *clientEncoding = GetDatabaseEncodingName(); const char *dbname = get_database_name(MyDatabaseId); int attemptIndex = 0; const char *keywordArray[] = { "host", "port", "fallback_application_name", "client_encoding", "connect_timeout", "dbname", "user", NULL }; char nodePortString[12]; const char *valueArray[] = { nodeName, nodePortString, "citus", clientEncoding, CLIENT_CONNECT_TIMEOUT_SECONDS, dbname, nodeUser, NULL }; sprintf(nodePortString, "%d", nodePort); Assert(sizeof(keywordArray) == sizeof(valueArray)); for (attemptIndex = 0; attemptIndex < MAX_CONNECT_ATTEMPTS; attemptIndex++) { connection = PQconnectdbParams(keywordArray, valueArray, false); if (PQstatus(connection) == CONNECTION_OK) { break; } else { /* warn if still erroring on final attempt */ if (attemptIndex == MAX_CONNECT_ATTEMPTS - 1) { WarnRemoteError(connection, NULL); } PQfinish(connection); connection = NULL; } } return connection; }
/* * Initialize client encoding if necessary. * called from InitPostgres() once during backend startup. */ void InitializeClientEncoding(void) { Assert(!backend_startup_complete); backend_startup_complete = true; if (SetClientEncoding(pending_client_encoding, true) < 0) { /* * Oops, the requested conversion is not available. We couldn't fail * before, but we can now. */ ereport(FATAL, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("conversion between %s and %s is not supported", pg_enc2name_tbl[pending_client_encoding].name, GetDatabaseEncodingName()))); } }
static void locate_stem_module(DictSnowball *d, char *lang) { const stemmer_module *m; /* * First, try to find exact match of stemmer module. Stemmer with * PG_SQL_ASCII encoding is treated as working with any server encoding */ for (m = stemmer_modules; m->name; m++) { if ((m->enc == PG_SQL_ASCII || m->enc == GetDatabaseEncoding()) && pg_strcasecmp(m->name, lang) == 0) { d->stem = m->stem; d->z = m->create(); d->needrecode = false; return; } } /* * Second, try to find stemmer for needed language for UTF8 encoding. */ for (m = stemmer_modules; m->name; m++) { if (m->enc == PG_UTF8 && pg_strcasecmp(m->name, lang) == 0) { d->stem = m->stem; d->z = m->create(); d->needrecode = true; return; } } ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("no Snowball stemmer available for language \"%s\" and encoding \"%s\"", lang, GetDatabaseEncodingName()))); }
/* * CheckMyDatabase -- fetch information from the pg_database entry for our DB */ static void CheckMyDatabase(const char *name, bool am_superuser) { HeapTuple tup; Form_pg_database dbform; char *collate; char *ctype; /* Fetch our pg_database row normally, via syscache */ tup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for database %u", MyDatabaseId); dbform = (Form_pg_database) GETSTRUCT(tup); /* This recheck is strictly paranoia */ if (strcmp(name, NameStr(dbform->datname)) != 0) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" has disappeared from pg_database", name), errdetail("Database OID %u now seems to belong to \"%s\".", MyDatabaseId, NameStr(dbform->datname)))); /* * Check permissions to connect to the database. * * These checks are not enforced when in standalone mode, so that there is * a way to recover from disabling all access to all databases, for * example "UPDATE pg_database SET datallowconn = false;". * * We do not enforce them for autovacuum worker processes either. */ if (IsUnderPostmaster && !IsAutoVacuumWorkerProcess()) { /* * Check that the database is currently allowing connections. */ if (!dbform->datallowconn) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("database \"%s\" is not currently accepting connections", name))); /* * Check privilege to connect to the database. (The am_superuser test * is redundant, but since we have the flag, might as well check it * and save a few cycles.) */ if (!am_superuser && pg_database_aclcheck(MyDatabaseId, GetUserId(), ACL_CONNECT) != ACLCHECK_OK) ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for database \"%s\"", name), errdetail("User does not have CONNECT privilege."))); /* * Check connection limit for this database. * * There is a race condition here --- we create our PGPROC before * checking for other PGPROCs. If two backends did this at about the * same time, they might both think they were over the limit, while * ideally one should succeed and one fail. Getting that to work * exactly seems more trouble than it is worth, however; instead we * just document that the connection limit is approximate. */ if (dbform->datconnlimit >= 0 && !am_superuser && CountDBBackends(MyDatabaseId) > dbform->datconnlimit) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("too many connections for database \"%s\"", name))); } /* * OK, we're golden. Next to-do item is to save the encoding info out of * the pg_database tuple. */ SetDatabaseEncoding(dbform->encoding); /* Record it as a GUC internal option, too */ SetConfigOption("server_encoding", GetDatabaseEncodingName(), PGC_INTERNAL, PGC_S_OVERRIDE); /* If we have no other source of client_encoding, use server encoding */ SetConfigOption("client_encoding", GetDatabaseEncodingName(), PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT); /* assign locale variables */ collate = NameStr(dbform->datcollate); ctype = NameStr(dbform->datctype); if (pg_perm_setlocale(LC_COLLATE, collate) == NULL) ereport(FATAL, (errmsg("database locale is incompatible with operating system"), errdetail("The database was initialized with LC_COLLATE \"%s\", " " which is not recognized by setlocale().", collate), errhint("Recreate the database with another locale or install the missing locale."))); if (pg_perm_setlocale(LC_CTYPE, ctype) == NULL) ereport(FATAL, (errmsg("database locale is incompatible with operating system"), errdetail("The database was initialized with LC_CTYPE \"%s\", " " which is not recognized by setlocale().", ctype), errhint("Recreate the database with another locale or install the missing locale."))); /* Make the locale settings visible as GUC variables, too */ SetConfigOption("lc_collate", collate, PGC_INTERNAL, PGC_S_OVERRIDE); SetConfigOption("lc_ctype", ctype, PGC_INTERNAL, PGC_S_OVERRIDE); ReleaseSysCache(tup); }
/* * CheckMyDatabase -- fetch information from the pg_database entry for our DB */ static void CheckMyDatabase(const char *name, bool am_superuser) { HeapTuple tup; Form_pg_database dbform; /* Fetch our pg_database row normally, via syscache */ tup = SearchSysCache(DATABASEOID, ObjectIdGetDatum(MyDatabaseId), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for database %u", MyDatabaseId); dbform = (Form_pg_database) GETSTRUCT(tup); /* This recheck is strictly paranoia */ if (strcmp(name, NameStr(dbform->datname)) != 0) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" has disappeared from pg_database", name), errdetail("Database OID %u now seems to belong to \"%s\".", MyDatabaseId, NameStr(dbform->datname)))); /* * Check permissions to connect to the database. * * These checks are not enforced when in standalone mode, so that there is * a way to recover from disabling all access to all databases, for * example "UPDATE pg_database SET datallowconn = false;". * * We do not enforce them for autovacuum worker processes either. */ if (IsUnderPostmaster && !IsAutoVacuumProcess()) { /* * Check that the database is currently allowing connections. */ if (!dbform->datallowconn) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("database \"%s\" is not currently accepting connections", name))); /* * Check privilege to connect to the database. (The am_superuser test * is redundant, but since we have the flag, might as well check it * and save a few cycles.) */ if (!am_superuser && pg_database_aclcheck(MyDatabaseId, GetUserId(), ACL_CONNECT) != ACLCHECK_OK) ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for database \"%s\"", name), errdetail("User does not have CONNECT privilege."))); /* * Check connection limit for this database. * * There is a race condition here --- we create our PGPROC before * checking for other PGPROCs. If two backends did this at about the * same time, they might both think they were over the limit, while * ideally one should succeed and one fail. Getting that to work * exactly seems more trouble than it is worth, however; instead we * just document that the connection limit is approximate. */ if (dbform->datconnlimit >= 0 && !am_superuser && CountDBBackends(MyDatabaseId) > dbform->datconnlimit) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("too many connections for database \"%s\"", name))); } /* * OK, we're golden. Next to-do item is to save the encoding info out of * the pg_database tuple. */ SetDatabaseEncoding(dbform->encoding); /* Record it as a GUC internal option, too */ SetConfigOption("server_encoding", GetDatabaseEncodingName(), PGC_INTERNAL, PGC_S_OVERRIDE); /* If we have no other source of client_encoding, use server encoding */ SetConfigOption("client_encoding", GetDatabaseEncodingName(), PGC_BACKEND, PGC_S_DEFAULT); /* Use the right encoding in translated messages */ #ifdef ENABLE_NLS pg_bind_textdomain_codeset(textdomain(NULL)); #endif /* * Lastly, set up any database-specific configuration variables. */ if (IsUnderPostmaster) { Datum datum; bool isnull; datum = SysCacheGetAttr(DATABASEOID, tup, Anum_pg_database_datconfig, &isnull); if (!isnull) { ArrayType *a = DatumGetArrayTypeP(datum); ProcessGUCArray(a, PGC_S_DATABASE); } } ReleaseSysCache(tup); }
/* * Connect to remote server using specified server and user mapping properties. */ static PGconn * connect_pg_server(ForeignServer *server, UserMapping *user) { PGconn *volatile conn = NULL; /* * Use PG_TRY block to ensure closing connection on error. */ PG_TRY(); { const char **keywords; const char **values; int n; /* * Construct connection params from generic options of ForeignServer * and UserMapping. (Some of them might not be libpq options, in * which case we'll just waste a few array slots.) Add 3 extra slots * for fallback_application_name, client_encoding, end marker. */ n = list_length(server->options) + list_length(user->options) + 3; keywords = (const char **) palloc(n * sizeof(char *)); values = (const char **) palloc(n * sizeof(char *)); n = 0; n += ExtractConnectionOptions(server->options, keywords + n, values + n); n += ExtractConnectionOptions(user->options, keywords + n, values + n); /* Use "postgres_fdw" as fallback_application_name. */ keywords[n] = "fallback_application_name"; values[n] = "postgres_fdw"; n++; /* Set client_encoding so that libpq can convert encoding properly. */ keywords[n] = "client_encoding"; values[n] = GetDatabaseEncodingName(); n++; keywords[n] = values[n] = NULL; /* verify connection parameters and make connection */ check_conn_params(keywords, values); conn = PQconnectdbParams(keywords, values, false); if (!conn || PQstatus(conn) != CONNECTION_OK) { char *connmessage; int msglen; /* libpq typically appends a newline, strip that */ connmessage = pstrdup(PQerrorMessage(conn)); msglen = strlen(connmessage); if (msglen > 0 && connmessage[msglen - 1] == '\n') connmessage[msglen - 1] = '\0'; ereport(ERROR, (errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION), errmsg("could not connect to server \"%s\"", server->servername), errdetail_internal("%s", connmessage))); } /* * Check that non-superuser has used password to establish connection; * otherwise, he's piggybacking on the postgres server's user * identity. See also dblink_security_check() in contrib/dblink. */ if (!superuser() && !PQconnectionUsedPassword(conn)) ereport(ERROR, (errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), errmsg("password is required"), errdetail("Non-superuser cannot connect if the server does not request a password."), errhint("Target server's authentication method must be changed."))); /* Prepare new session for use */ configure_remote_session(conn); pfree(keywords); pfree(values); } PG_CATCH(); { /* Release PGconn data structure if we managed to create one */ if (conn) PQfinish(conn); PG_RE_THROW(); } PG_END_TRY(); return conn; }
/* * Verify mbstr to make sure that it has a valid character sequence. * mbstr is not necessarily NULL terminated; length of mbstr is * specified by len. * * If OK, return TRUE. If a problem is found, return FALSE when noError is * true; when noError is false, ereport() a descriptive message. */ bool pg_verifymbstr(const unsigned char *mbstr, int len, bool noError) { int l; int i; int encoding; /* we do not need any check in single-byte encodings */ if (pg_database_encoding_max_length() <= 1) return true; encoding = GetDatabaseEncoding(); while (len > 0 && *mbstr) { /* special UTF-8 check */ if (encoding == PG_UTF8 && (*mbstr & 0xf8) == 0xf0) { if (noError) return false; ereport(ERROR, (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), errmsg("Unicode characters greater than or equal to 0x10000 are not supported"))); } l = pg_mblen(mbstr); for (i = 1; i < l; i++) { /* * we expect that every multibyte char consists of bytes * having the 8th bit set */ if (i >= len || (mbstr[i] & 0x80) == 0) { char buf[8 * 2 + 1]; char *p = buf; int j, jlimit; if (noError) return false; jlimit = Min(l, len); jlimit = Min(jlimit, 8); /* prevent buffer overrun */ for (j = 0; j < jlimit; j++) p += sprintf(p, "%02x", mbstr[j]); ereport(ERROR, (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), errmsg("invalid byte sequence for encoding \"%s\": 0x%s", GetDatabaseEncodingName(), buf))); } } len -= l; mbstr += l; } return true; }
static PGconn * connect_to_localhost(void) { PGconn *conn; char sql[1024]; char *host; char dbName[1024]; /* Also ensure backend isn't confused by this environment var. */ setenv("PGCLIENTENCODING", GetDatabaseEncodingName(), 1); #ifdef HAVE_UNIX_SOCKETS host = (UnixSocketDir == NULL || UnixSocketDir[0] == '\0') ? DEFAULT_PGSOCKET_DIR : UnixSocketDir; #else host = "localhost"; #endif /* set dbname and disable hostaddr */ snprintf(dbName, lengthof(dbName), "dbname='%s' hostaddr=''", escape_param_str(get_database_name(MyDatabaseId))); conn = PQsetdbLogin( host, GetConfigOption("port", false, false), NULL, NULL, dbName, GetUserNameFromId(GetUserId()), NULL); if (PQstatus(conn) == CONNECTION_BAD) { ParallelWriter wr; wr.conn = conn; ereport(ERROR, (errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION), errmsg("could not establish connection to parallel writer"), errdetail("%s", finish_and_get_message(&wr)), errhint("Refer to the following if it is an authentication " "error. Specifies the authentication method to " "without the need for a password in pg_hba.conf (ex. " "trust or ident), or specify the password to the " "password file of the operating system user who ran " "PostgreSQL server. If cannot use these solution, " "specify WRITER=DIRECT."))); } /* attempt to set default datestyle */ snprintf(sql, lengthof(sql), "SET datestyle = '%s'", GetConfigOption("datestyle", false, false)); PQexec(conn, sql); /* attempt to set default datestyle */ snprintf(sql, lengthof(sql), "SET timezone = '%s'", show_timezone()); PQexec(conn, sql); /* set message receiver */ PQsetNoticeReceiver(conn, transfer_message, NULL); return conn; }
/* -------------------------------- * ReverifyMyDatabase * * Since we are forced to fetch the database OID out of pg_database without * benefit of locking or transaction ID checking (see utils/misc/database.c), * we might have gotten a wrong answer. Or, we might have attached to a * database that's in process of being destroyed by destroydb(). This * routine is called after we have all the locking and other infrastructure * running --- now we can check that we are really attached to a valid * database. * * In reality, if destroydb() is running in parallel with our startup, * it's pretty likely that we will have failed before now, due to being * unable to read some of the system tables within the doomed database. * This routine just exists to make *sure* we have not started up in an * invalid database. If we quit now, we should have managed to avoid * creating any serious problems. * * This is also a handy place to fetch the database encoding info out * of pg_database. * * To avoid having to read pg_database more times than necessary * during session startup, this place is also fitting to set up any * database-specific configuration variables. * -------------------------------- */ static void ReverifyMyDatabase(const char *name) { Relation pgdbrel; HeapScanDesc pgdbscan; ScanKeyData key; HeapTuple tup; Form_pg_database dbform; /* * Because we grab AccessShareLock here, we can be sure that destroydb * is not running in parallel with us (any more). */ pgdbrel = heap_openr(DatabaseRelationName, AccessShareLock); ScanKeyEntryInitialize(&key, 0, Anum_pg_database_datname, F_NAMEEQ, NameGetDatum(name)); pgdbscan = heap_beginscan(pgdbrel, SnapshotNow, 1, &key); tup = heap_getnext(pgdbscan, ForwardScanDirection); if (!HeapTupleIsValid(tup) || HeapTupleGetOid(tup) != MyDatabaseId) { /* OOPS */ heap_close(pgdbrel, AccessShareLock); /* * The only real problem I could have created is to load dirty * buffers for the dead database into shared buffer cache; if I * did, some other backend will eventually try to write them and * die in mdblindwrt. Flush any such pages to forestall trouble. */ DropBuffers(MyDatabaseId); /* Now I can commit hara-kiri with a clear conscience... */ ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\", OID %u, has disappeared from pg_database", name, MyDatabaseId))); } /* * Also check that the database is currently allowing connections. * (We do not enforce this in standalone mode, however, so that there is * a way to recover from "UPDATE pg_database SET datallowconn = false;") */ dbform = (Form_pg_database) GETSTRUCT(tup); if (IsUnderPostmaster && !dbform->datallowconn) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("database \"%s\" is not currently accepting connections", name))); /* * OK, we're golden. Only other to-do item is to save the encoding * info out of the pg_database tuple. */ SetDatabaseEncoding(dbform->encoding); /* Record it as a GUC internal option, too */ SetConfigOption("server_encoding", GetDatabaseEncodingName(), PGC_INTERNAL, PGC_S_OVERRIDE); /* If we have no other source of client_encoding, use server encoding */ SetConfigOption("client_encoding", GetDatabaseEncodingName(), PGC_BACKEND, PGC_S_DEFAULT); /* * Set up database-specific configuration variables. */ if (IsUnderPostmaster) { Datum datum; bool isnull; datum = heap_getattr(tup, Anum_pg_database_datconfig, RelationGetDescr(pgdbrel), &isnull); if (!isnull) { ArrayType *a = DatumGetArrayTypeP(datum); ProcessGUCArray(a, PGC_S_DATABASE); } } heap_endscan(pgdbscan); heap_close(pgdbrel, AccessShareLock); }