#include "foreign/foreign.h"#include "lib/stringinfo.h"#include "nodes/relation.h"#include "utils/rel.h"#include "libpq-fe.h"

Go to the source code of this file.
| void appendWhereClause | ( | StringInfo | buf, | |
| PlannerInfo * | root, | |||
| RelOptInfo * | baserel, | |||
| List * | exprs, | |||
| bool | is_first, | |||
| List ** | params | |||
| ) |
Definition at line 779 of file deparse.c.
References appendStringInfoChar(), appendStringInfoString(), deparse_expr_cxt::buf, RestrictInfo::clause, deparseExpr(), deparse_expr_cxt::foreignrel, lfirst, deparse_expr_cxt::params_list, reset_transmission_modes(), deparse_expr_cxt::root, and set_transmission_modes().
Referenced by estimate_path_cost_size(), and postgresGetForeignPlan().
{
deparse_expr_cxt context;
int nestlevel;
ListCell *lc;
if (params)
*params = NIL; /* initialize result list to empty */
/* Set up context struct for recursion */
context.root = root;
context.foreignrel = baserel;
context.buf = buf;
context.params_list = params;
/* Make sure any constants in the exprs are printed portably */
nestlevel = set_transmission_modes();
foreach(lc, exprs)
{
RestrictInfo *ri = (RestrictInfo *) lfirst(lc);
/* Connect expressions with "AND" and parenthesize each condition. */
if (is_first)
appendStringInfoString(buf, " WHERE ");
else
appendStringInfoString(buf, " AND ");
appendStringInfoChar(buf, '(');
deparseExpr(ri->clause, &context);
appendStringInfoChar(buf, ')');
is_first = false;
}
reset_transmission_modes(nestlevel);
}
| void classifyConditions | ( | PlannerInfo * | root, | |
| RelOptInfo * | baserel, | |||
| List ** | remote_conds, | |||
| List ** | local_conds | |||
| ) |
Definition at line 143 of file deparse.c.
References RelOptInfo::baserestrictinfo, RestrictInfo::clause, is_foreign_expr(), lappend(), and lfirst.
Referenced by postgresGetForeignRelSize().
{
ListCell *lc;
*remote_conds = NIL;
*local_conds = NIL;
foreach(lc, baserel->baserestrictinfo)
{
RestrictInfo *ri = (RestrictInfo *) lfirst(lc);
if (is_foreign_expr(root, baserel, ri->clause))
*remote_conds = lappend(*remote_conds, ri);
else
*local_conds = lappend(*local_conds, ri);
}
}
| void deparseAnalyzeSizeSql | ( | StringInfo | buf, | |
| Relation | rel | |||
| ) |
Definition at line 984 of file deparse.c.
References appendStringInfo(), StringInfoData::data, deparseRelation(), deparseStringLiteral(), and initStringInfo().
Referenced by postgresAnalyzeForeignTable().
{
StringInfoData relname;
/* We'll need the remote relation name as a literal. */
initStringInfo(&relname);
deparseRelation(&relname, rel);
appendStringInfo(buf, "SELECT pg_catalog.pg_relation_size(");
deparseStringLiteral(buf, relname.data);
appendStringInfo(buf, "::pg_catalog.regclass) / %d", BLCKSZ);
}
| void deparseAnalyzeSql | ( | StringInfo | buf, | |
| Relation | rel, | |||
| List ** | retrieved_attrs | |||
| ) |
Definition at line 1004 of file deparse.c.
References appendStringInfoString(), tupleDesc::attrs, defGetString(), DefElem::defname, deparseRelation(), GetForeignColumnOptions(), i, lappend_int(), lfirst, NameStr, tupleDesc::natts, quote_identifier(), RelationGetDescr, and RelationGetRelid.
Referenced by postgresAcquireSampleRowsFunc().
{
Oid relid = RelationGetRelid(rel);
TupleDesc tupdesc = RelationGetDescr(rel);
int i;
char *colname;
List *options;
ListCell *lc;
bool first = true;
*retrieved_attrs = NIL;
appendStringInfoString(buf, "SELECT ");
for (i = 0; i < tupdesc->natts; i++)
{
/* Ignore dropped columns. */
if (tupdesc->attrs[i]->attisdropped)
continue;
if (!first)
appendStringInfoString(buf, ", ");
first = false;
/* Use attribute name or column_name option. */
colname = NameStr(tupdesc->attrs[i]->attname);
options = GetForeignColumnOptions(relid, i + 1);
foreach(lc, options)
{
DefElem *def = (DefElem *) lfirst(lc);
if (strcmp(def->defname, "column_name") == 0)
{
colname = defGetString(def);
break;
}
}
appendStringInfoString(buf, quote_identifier(colname));
*retrieved_attrs = lappend_int(*retrieved_attrs, i + 1);
}
/* Don't generate bad syntax for zero-column relation. */
if (first)
appendStringInfoString(buf, "NULL");
/*
* Construct FROM clause
*/
appendStringInfoString(buf, " FROM ");
deparseRelation(buf, rel);
}
| void deparseDeleteSql | ( | StringInfo | buf, | |
| PlannerInfo * | root, | |||
| Index | rtindex, | |||
| Relation | rel, | |||
| List * | returningList, | |||
| List ** | retrieved_attrs | |||
| ) |
Definition at line 936 of file deparse.c.
References appendStringInfoString(), deparseRelation(), and deparseReturningList().
Referenced by postgresPlanForeignModify().
{
appendStringInfoString(buf, "DELETE FROM ");
deparseRelation(buf, rel);
appendStringInfoString(buf, " WHERE ctid = $1");
if (returningList)
deparseReturningList(buf, root, rtindex, rel, returningList,
retrieved_attrs);
else
*retrieved_attrs = NIL;
}
| void deparseInsertSql | ( | StringInfo | buf, | |
| PlannerInfo * | root, | |||
| Index | rtindex, | |||
| Relation | rel, | |||
| List * | targetAttrs, | |||
| List * | returningList, | |||
| List ** | retrieved_attrs | |||
| ) |
Definition at line 830 of file deparse.c.
References appendStringInfo(), appendStringInfoString(), deparseColumnRef(), deparseRelation(), deparseReturningList(), and lfirst_int.
Referenced by postgresPlanForeignModify().
{
AttrNumber pindex;
bool first;
ListCell *lc;
appendStringInfoString(buf, "INSERT INTO ");
deparseRelation(buf, rel);
if (targetAttrs)
{
appendStringInfoString(buf, "(");
first = true;
foreach(lc, targetAttrs)
{
int attnum = lfirst_int(lc);
if (!first)
appendStringInfoString(buf, ", ");
first = false;
deparseColumnRef(buf, rtindex, attnum, root);
}
appendStringInfoString(buf, ") VALUES (");
pindex = 1;
first = true;
foreach(lc, targetAttrs)
{
if (!first)
appendStringInfoString(buf, ", ");
first = false;
appendStringInfo(buf, "$%d", pindex);
pindex++;
}
appendStringInfoString(buf, ")");
}
else
appendStringInfoString(buf, " DEFAULT VALUES");
if (returningList)
deparseReturningList(buf, root, rtindex, rel, returningList,
retrieved_attrs);
else
*retrieved_attrs = NIL;
}
| void deparseSelectSql | ( | StringInfo | buf, | |
| PlannerInfo * | root, | |||
| RelOptInfo * | baserel, | |||
| Bitmapset * | attrs_used, | |||
| List ** | retrieved_attrs | |||
| ) |
Definition at line 662 of file deparse.c.
References appendStringInfoString(), deparseRelation(), deparseTargetList(), heap_close, heap_open(), NoLock, planner_rt_fetch, RangeTblEntry::relid, and RelOptInfo::relid.
Referenced by estimate_path_cost_size(), and postgresGetForeignPlan().
{
RangeTblEntry *rte = planner_rt_fetch(baserel->relid, root);
Relation rel;
/*
* Core code already has some lock on each rel being planned, so we can
* use NoLock here.
*/
rel = heap_open(rte->relid, NoLock);
/*
* Construct SELECT list
*/
appendStringInfoString(buf, "SELECT ");
deparseTargetList(buf, root, baserel->relid, rel, attrs_used,
retrieved_attrs);
/*
* Construct FROM clause
*/
appendStringInfoString(buf, " FROM ");
deparseRelation(buf, rel);
heap_close(rel, NoLock);
}
| void deparseUpdateSql | ( | StringInfo | buf, | |
| PlannerInfo * | root, | |||
| Index | rtindex, | |||
| Relation | rel, | |||
| List * | targetAttrs, | |||
| List * | returningList, | |||
| List ** | retrieved_attrs | |||
| ) |
Definition at line 892 of file deparse.c.
References appendStringInfo(), appendStringInfoString(), deparseColumnRef(), deparseRelation(), deparseReturningList(), and lfirst_int.
Referenced by postgresPlanForeignModify().
{
AttrNumber pindex;
bool first;
ListCell *lc;
appendStringInfoString(buf, "UPDATE ");
deparseRelation(buf, rel);
appendStringInfoString(buf, " SET ");
pindex = 2; /* ctid is always the first param */
first = true;
foreach(lc, targetAttrs)
{
int attnum = lfirst_int(lc);
if (!first)
appendStringInfoString(buf, ", ");
first = false;
deparseColumnRef(buf, rtindex, attnum, root);
appendStringInfo(buf, " = $%d", pindex);
pindex++;
}
appendStringInfoString(buf, " WHERE ctid = $1");
if (returningList)
deparseReturningList(buf, root, rtindex, rel, returningList,
retrieved_attrs);
else
*retrieved_attrs = NIL;
}
| int ExtractConnectionOptions | ( | List * | defelems, | |
| const char ** | keywords, | |||
| const char ** | values | |||
| ) |
Definition at line 271 of file option.c.
References defGetString(), DefElem::defname, i, InitPgFdwOptions(), is_libpq_option(), and lfirst.
Referenced by connect_pg_server().
{
ListCell *lc;
int i;
/* Build our options lists if we didn't yet. */
InitPgFdwOptions();
i = 0;
foreach(lc, defelems)
{
DefElem *d = (DefElem *) lfirst(lc);
if (is_libpq_option(d->defname))
{
keywords[i] = d->defname;
values[i] = defGetString(d);
i++;
}
}
return i;
}
| PGconn* GetConnection | ( | ForeignServer * | server, | |
| UserMapping * | user, | |||
| bool | will_prep_stmt | |||
| ) |
Definition at line 97 of file connection.c.
References begin_remote_xact(), CacheMemoryContext, ConnCacheEntry::conn, connect_pg_server(), DEBUG3, elog, HASHCTL::entrysize, HASHCTL::hash, HASH_CONTEXT, hash_create(), HASH_ELEM, HASH_ENTER, HASH_FUNCTION, hash_search(), ConnCacheEntry::have_error, ConnCacheEntry::have_prep_stmt, HASHCTL::hcxt, HASHCTL::keysize, MemSet, NULL, pgfdw_subxact_callback(), pgfdw_xact_callback(), RegisterSubXactCallback(), RegisterXactCallback(), ForeignServer::serverid, ConnCacheKey::serverid, ForeignServer::servername, UserMapping::userid, ConnCacheKey::userid, ConnCacheEntry::xact_depth, and xact_got_connection.
Referenced by BaseBackup(), dumpBlobs(), dumpDatabase(), dumpTableData_copy(), estimate_path_cost_size(), expand_schema_name_patterns(), expand_table_name_patterns(), getTables(), main(), postgresAcquireSampleRowsFunc(), postgresAnalyzeForeignTable(), postgresBeginForeignModify(), postgresBeginForeignScan(), setup_connection(), StartLogStreamer(), and StreamLog().
{
bool found;
ConnCacheEntry *entry;
ConnCacheKey key;
/* First time through, initialize connection cache hashtable */
if (ConnectionHash == NULL)
{
HASHCTL ctl;
MemSet(&ctl, 0, sizeof(ctl));
ctl.keysize = sizeof(ConnCacheKey);
ctl.entrysize = sizeof(ConnCacheEntry);
ctl.hash = tag_hash;
/* allocate ConnectionHash in the cache context */
ctl.hcxt = CacheMemoryContext;
ConnectionHash = hash_create("postgres_fdw connections", 8,
&ctl,
HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
/*
* Register some callback functions that manage connection cleanup.
* This should be done just once in each backend.
*/
RegisterXactCallback(pgfdw_xact_callback, NULL);
RegisterSubXactCallback(pgfdw_subxact_callback, NULL);
}
/* Set flag that we did GetConnection during the current transaction */
xact_got_connection = true;
/* Create hash key for the entry. Assume no pad bytes in key struct */
key.serverid = server->serverid;
key.userid = user->userid;
/*
* Find or create cached entry for requested connection.
*/
entry = hash_search(ConnectionHash, &key, HASH_ENTER, &found);
if (!found)
{
/* initialize new hashtable entry (key is already filled in) */
entry->conn = NULL;
entry->xact_depth = 0;
entry->have_prep_stmt = false;
entry->have_error = false;
}
/*
* We don't check the health of cached connection here, because it would
* require some overhead. Broken connection will be detected when the
* connection is actually used.
*/
/*
* If cache entry doesn't have a connection, we have to establish a new
* connection. (If connect_pg_server throws an error, the cache entry
* will be left in a valid empty state.)
*/
if (entry->conn == NULL)
{
entry->xact_depth = 0; /* just to be sure */
entry->have_prep_stmt = false;
entry->have_error = false;
entry->conn = connect_pg_server(server, user);
elog(DEBUG3, "new postgres_fdw connection %p for server \"%s\"",
entry->conn, server->servername);
}
/*
* Start a new transaction or subtransaction if needed.
*/
begin_remote_xact(entry);
/* Remember if caller will prepare statements */
entry->have_prep_stmt |= will_prep_stmt;
return entry->conn;
}
| unsigned int GetCursorNumber | ( | PGconn * | conn | ) |
Definition at line 433 of file connection.c.
References cursor_number.
Referenced by postgresAcquireSampleRowsFunc(), and postgresBeginForeignScan().
{
return ++cursor_number;
}
| unsigned int GetPrepStmtNumber | ( | PGconn * | conn | ) |
Definition at line 447 of file connection.c.
References prep_stmt_number.
Referenced by prepare_foreign_modify().
{
return ++prep_stmt_number;
}
| bool is_foreign_expr | ( | PlannerInfo * | root, | |
| RelOptInfo * | baserel, | |||
| Expr * | expr | |||
| ) |
Definition at line 168 of file deparse.c.
References Assert, foreign_loc_cxt::collation, contain_mutable_functions(), FDW_COLLATE_NONE, foreign_expr_walker(), foreign_glob_cxt::foreignrel, InvalidOid, foreign_glob_cxt::root, and foreign_loc_cxt::state.
Referenced by classifyConditions(), postgresGetForeignPaths(), and postgresGetForeignPlan().
{
foreign_glob_cxt glob_cxt;
foreign_loc_cxt loc_cxt;
/*
* Check that the expression consists of nodes that are safe to execute
* remotely.
*/
glob_cxt.root = root;
glob_cxt.foreignrel = baserel;
loc_cxt.collation = InvalidOid;
loc_cxt.state = FDW_COLLATE_NONE;
if (!foreign_expr_walker((Node *) expr, &glob_cxt, &loc_cxt))
return false;
/* Expressions examined here should be boolean, ie noncollatable */
Assert(loc_cxt.collation == InvalidOid);
Assert(loc_cxt.state == FDW_COLLATE_NONE);
/*
* An expression which includes any mutable functions can't be sent over
* because its result is not stable. For example, sending now() remote
* side could cause confusion from clock offsets. Future versions might
* be able to make this choice with more granularity. (We check this last
* because it requires a lot of expensive catalog lookups.)
*/
if (contain_mutable_functions((Node *) expr))
return false;
/* OK to evaluate on the remote server */
return true;
}
Definition at line 465 of file connection.c.
References ereport, errcode(), errcontext, errdetail_internal(), errhint(), errmsg(), errmsg_internal(), MAKE_SQLSTATE, PG_CATCH, PG_DIAG_CONTEXT, PG_DIAG_MESSAGE_DETAIL, PG_DIAG_MESSAGE_HINT, PG_DIAG_MESSAGE_PRIMARY, PG_DIAG_SQLSTATE, PG_END_TRY, PG_RE_THROW, PG_TRY, PQclear(), and PQresultErrorField().
Referenced by close_cursor(), create_cursor(), do_sql_command(), fetch_more_data(), get_remote_estimate(), pgfdw_subxact_callback(), pgfdw_xact_callback(), postgresAcquireSampleRowsFunc(), postgresAnalyzeForeignTable(), postgresEndForeignModify(), postgresExecForeignDelete(), postgresExecForeignInsert(), postgresExecForeignUpdate(), postgresReScanForeignScan(), and prepare_foreign_modify().
{
/* If requested, PGresult must be released before leaving this function. */
PG_TRY();
{
char *diag_sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
char *message_primary = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
char *message_detail = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL);
char *message_hint = PQresultErrorField(res, PG_DIAG_MESSAGE_HINT);
char *message_context = PQresultErrorField(res, PG_DIAG_CONTEXT);
int sqlstate;
if (diag_sqlstate)
sqlstate = MAKE_SQLSTATE(diag_sqlstate[0],
diag_sqlstate[1],
diag_sqlstate[2],
diag_sqlstate[3],
diag_sqlstate[4]);
else
sqlstate = ERRCODE_CONNECTION_FAILURE;
ereport(elevel,
(errcode(sqlstate),
message_primary ? errmsg_internal("%s", message_primary) :
errmsg("unknown error"),
message_detail ? errdetail_internal("%s", message_detail) : 0,
message_hint ? errhint("%s", message_hint) : 0,
message_context ? errcontext("%s", message_context) : 0,
sql ? errcontext("Remote SQL command: %s", sql) : 0));
}
PG_CATCH();
{
if (clear)
PQclear(res);
PG_RE_THROW();
}
PG_END_TRY();
if (clear)
PQclear(res);
}
| void ReleaseConnection | ( | PGconn * | conn | ) |
Definition at line 412 of file connection.c.
Referenced by estimate_path_cost_size(), postgresAcquireSampleRowsFunc(), postgresAnalyzeForeignTable(), postgresEndForeignModify(), and postgresEndForeignScan().
{
/*
* Currently, we don't actually track connection references because all
* cleanup is managed on a transaction or subtransaction basis instead. So
* there's nothing to do here.
*/
}
| void reset_transmission_modes | ( | int | nestlevel | ) |
Definition at line 2050 of file postgres_fdw.c.
References AtEOXact_GUC().
Referenced by appendWhereClause(), convert_prep_stmt_params(), and create_cursor().
{
AtEOXact_GUC(true, nestlevel);
}
| int set_transmission_modes | ( | void | ) |
Definition at line 2022 of file postgres_fdw.c.
References DateStyle, extra_float_digits, GUC_ACTION_SAVE, IntervalStyle, INTSTYLE_POSTGRES, NewGUCNestLevel(), PGC_S_SESSION, PGC_USERSET, set_config_option(), and USE_ISO_DATES.
Referenced by appendWhereClause(), convert_prep_stmt_params(), and create_cursor().
{
int nestlevel = NewGUCNestLevel();
/*
* The values set here should match what pg_dump does. See also
* configure_remote_session in connection.c.
*/
if (DateStyle != USE_ISO_DATES)
(void) set_config_option("datestyle", "ISO",
PGC_USERSET, PGC_S_SESSION,
GUC_ACTION_SAVE, true, 0);
if (IntervalStyle != INTSTYLE_POSTGRES)
(void) set_config_option("intervalstyle", "postgres",
PGC_USERSET, PGC_S_SESSION,
GUC_ACTION_SAVE, true, 0);
if (extra_float_digits < 3)
(void) set_config_option("extra_float_digits", "3",
PGC_USERSET, PGC_S_SESSION,
GUC_ACTION_SAVE, true, 0);
return nestlevel;
}
1.7.1