/* * CStoreTable checks if the given table name belongs to a foreign columnar store * table. If it does, the function returns true. Otherwise, it returns false. */ static bool CStoreTable(RangeVar *rangeVar) { bool cstoreTable = false; Relation relation = heap_openrv(rangeVar, AccessShareLock); Oid relationId = RelationGetRelid(relation); char relationKind = get_rel_relkind(relationId); if (relationKind == RELKIND_FOREIGN_TABLE) { ForeignTable *foreignTable = GetForeignTable(relationId); ForeignServer *server = GetForeignServer(foreignTable->serverid); ForeignDataWrapper *foreignDataWrapper = GetForeignDataWrapper(server->fdwid); char *foreignWrapperName = foreignDataWrapper->fdwname; if (strncmp(foreignWrapperName, CSTORE_FDW_NAME, NAMEDATALEN) == 0) { cstoreTable = true; } } heap_close(relation, AccessShareLock); return cstoreTable; }
void tdsGetForeignTableOptionsFromCatalog(Oid foreigntableid, TdsFdwOptionSet* option_set) { ForeignTable *f_table; ForeignServer *f_server; UserMapping *f_mapping; #ifdef DEBUG ereport(NOTICE, (errmsg("----> starting tdsGetForeignTableOptionsFromCatalog") )); #endif tdsOptionSetInit(option_set); f_table = GetForeignTable(foreigntableid); f_server = GetForeignServer(f_table->serverid); f_mapping = GetUserMapping(GetUserId(), f_table->serverid); tdsGetForeignServerOptions(f_server->options, option_set); tdsGetForeignServerTableOptions(f_server->options, option_set); tdsGetForeignTableOptions(f_table->options, option_set); tdsGetUserMappingOptions(f_mapping->options, option_set); tdsSetDefaultOptions(option_set); tdsValidateOptionSet(option_set); #ifdef DEBUG ereport(NOTICE, (errmsg("----> finishing tdsGetForeignTableOptionsFromCatalog") )); #endif }
/* * pg_get_extensiondef_string finds the foreign data wrapper that corresponds to * the given foreign tableId, and checks if an extension owns this foreign data * wrapper. If it does, the function returns the extension's definition. If not, * the function returns null. */ char * pg_get_extensiondef_string(Oid tableRelationId) { ForeignTable *foreignTable = GetForeignTable(tableRelationId); ForeignServer *server = GetForeignServer(foreignTable->serverid); ForeignDataWrapper *foreignDataWrapper = GetForeignDataWrapper(server->fdwid); StringInfoData buffer = { NULL, 0, 0, 0 }; Oid classId = ForeignDataWrapperRelationId; Oid objectId = server->fdwid; Oid extensionId = getExtensionOfObject(classId, objectId); if (OidIsValid(extensionId)) { char *extensionName = get_extension_name(extensionId); Oid extensionSchemaId = get_extension_schema(extensionId); char *extensionSchema = get_namespace_name(extensionSchemaId); initStringInfo(&buffer); appendStringInfo(&buffer, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s", quote_identifier(extensionName), quote_identifier(extensionSchema)); } else { ereport(NOTICE, (errmsg("foreign-data wrapper \"%s\" does not have an " "extension defined", foreignDataWrapper->fdwname))); } return (buffer.data); }
/* * pg_get_serverdef_string finds the foreign server that corresponds to the * given foreign tableId, and returns this server's definition. */ char * pg_get_serverdef_string(Oid tableRelationId) { ForeignTable *foreignTable = GetForeignTable(tableRelationId); ForeignServer *server = GetForeignServer(foreignTable->serverid); ForeignDataWrapper *foreignDataWrapper = GetForeignDataWrapper(server->fdwid); StringInfoData buffer = { NULL, 0, 0, 0 }; initStringInfo(&buffer); appendStringInfo(&buffer, "CREATE SERVER %s", quote_identifier(server->servername)); if (server->servertype != NULL) { appendStringInfo(&buffer, " TYPE %s", quote_literal_cstr(server->servertype)); } if (server->serverversion != NULL) { appendStringInfo(&buffer, " VERSION %s", quote_literal_cstr(server->serverversion)); } appendStringInfo(&buffer, " FOREIGN DATA WRAPPER %s", quote_identifier(foreignDataWrapper->fdwname)); /* append server options, if any */ AppendOptionListToString(&buffer, server->options); return (buffer.data); }
/* * GetForeignServerByName - look up the foreign server definition by name. */ ForeignServer * GetForeignServerByName(const char *srvname, bool missing_ok) { Oid serverid = GetForeignServerOidByName(srvname, missing_ok); if (!OidIsValid(serverid) && missing_ok) return NULL; return GetForeignServer(serverid); }
/* * GetForeignServerByName - look up the foreign server definition by name. */ ForeignServer * GetForeignServerByName(const char *srvname, bool missing_ok) { Oid serverid = get_foreign_server_oid(srvname, missing_ok); if (!OidIsValid(serverid)) return NULL; return GetForeignServer(serverid); }
static void getTableOptions(Oid foreigntableid,struct ktTableOptions *table_options) { ForeignTable *table; ForeignServer *server; UserMapping *mapping; List *options; ListCell *lc; #ifdef DEBUG elog(NOTICE, "getTableOptions"); #endif /* * Extract options from FDW objects. We only need to worry about server * options for Redis * */ table = GetForeignTable(foreigntableid); server = GetForeignServer(table->serverid); mapping = GetUserMapping(GetUserId(), table->serverid); table_options->userId = mapping->userid; table_options->serverId = server->serverid; options = NIL; options = list_concat(options, table->options); options = list_concat(options, server->options); options = list_concat(options, mapping->options); // table_options->table_type = PG_REDIS_SCALAR_TABLE; /* Loop through the options, and get the server/port */ foreach(lc, options) { DefElem *def = (DefElem *) lfirst(lc); if (strcmp(def->defname, "host") == 0) table_options->host = defGetString(def); if (strcmp(def->defname, "port") == 0) table_options->port = atoi(defGetString(def)); if (strcmp(def->defname, "timeout") == 0) table_options->timeout = atoi(defGetString(def)); }
/* * CStoreTable returns true if the given relationId belongs to a foreign cstore * table, otherwise it returns false. */ bool CStoreTable(Oid relationId) { bool cstoreTable = false; char relationKind = get_rel_relkind(relationId); if (relationKind == RELKIND_FOREIGN_TABLE) { ForeignTable *foreignTable = GetForeignTable(relationId); ForeignServer *server = GetForeignServer(foreignTable->serverid); ForeignDataWrapper *foreignDataWrapper = GetForeignDataWrapper(server->fdwid); if (strncmp(foreignDataWrapper->fdwname, CSTORE_FDW_NAME, NAMEDATALEN) == 0) { cstoreTable = true; } } return cstoreTable; }
static void getTableOptions(Oid foreigntableid, struct wdbTableOptions *table_options) { ForeignTable* table; ForeignServer* server; UserMapping* mapping; List* options = NIL; ListCell* lc = NULL; #ifdef DEBUG elog(NOTICE, "getTableOptions"); #endif /* * Extract options from FDW objects. * */ table = GetForeignTable(foreigntableid); server = GetForeignServer(table->serverid); mapping = GetUserMapping(GetUserId(), table->serverid); table_options->userId = mapping->userid; table_options->serverId = server->serverid; options = NIL; options = list_concat(options, table->options); options = list_concat(options, server->options); options = list_concat(options, mapping->options); /* Loop through the options, and get the server/port */ foreach(lc, options) { DefElem *def = (DefElem *) lfirst(lc); if (strcmp(def->defname, "address") == 0) table_options->address = defGetString(def); if (strcmp(def->defname, "size") == 0) table_options->size = atoi(defGetString(def)); }
static javaFdwExecutionState* javaGetOptions(Oid foreigntableid) { ForeignTable *f_table; ForeignServer *f_server; UserMapping *f_mapping; List *options; ListCell *cell; jobject obj, res, serverClass; jmethodID serverConstructor; jclass cl; javaFdwExecutionState *state; char *classname = NULL; options = NIL; f_table = GetForeignTable(foreigntableid); options = list_concat(options, f_table->options); f_server = GetForeignServer(f_table->serverid); options = list_concat(options, f_server->options); PG_TRY(); { f_mapping = GetUserMapping(GetUserId(), f_table->serverid); options = list_concat(options, f_mapping->options); } PG_CATCH(); { FlushErrorState(); /* DO NOTHING HERE */ } PG_END_TRY(); foreach(cell, options) { DefElem *def = (DefElem *) lfirst(cell); if (strcmp(def->defname, "class") == 0) { classname = (char *) defGetString(def); } }
wxString pgForeignTable::GetSql(ctlTree *browser) { if (sql.IsNull()) { sql = wxT("-- Foreign Table: ") + GetQuotedFullIdentifier() + wxT("\n\n") + wxT("-- DROP FOREIGN TABLE ") + GetQuotedFullIdentifier() + wxT(";") + wxT("\n\nCREATE FOREIGN TABLE ") + GetQuotedFullIdentifier() + wxT("\n (") + GetQuotedTypesList() + wxT(")\n SERVER ") + GetForeignServer(); if (!GetOptionsList().IsEmpty()) sql += wxT("\n OPTIONS (") + GetOptionsList() + wxT(")"); sql += wxT(";\n") + GetOwnerSql(9, 1) + GetCommentSql(); if (GetConnection()->BackendMinimumVersion(9, 1)) sql += GetSeqLabelsSql(); } return sql; }
/* * pg_get_tableschemadef_string returns the definition of a given table. This * definition includes table's schema, default column values, not null and check * constraints. The definition does not include constraints that trigger index * creations; specifically, unique and primary key constraints are excluded. */ static char * pg_shard_get_tableschemadef_string(Oid tableRelationId) { Relation relation = NULL; char *relationName = NULL; char relationKind = 0; TupleDesc tupleDescriptor = NULL; TupleConstr *tupleConstraints = NULL; int attributeIndex = 0; bool firstAttributePrinted = false; AttrNumber defaultValueIndex = 0; AttrNumber constraintIndex = 0; AttrNumber constraintCount = 0; StringInfoData buffer = { NULL, 0, 0, 0 }; /* * Instead of retrieving values from system catalogs as other functions in * ruleutils.c do, we follow an unusual approach here: we open the relation, * and fetch the relation's tuple descriptor. We do this because the tuple * descriptor already contains information harnessed from pg_attrdef, * pg_attribute, pg_constraint, and pg_class; and therefore using the * descriptor saves us from a lot of additional work. */ relation = relation_open(tableRelationId, AccessShareLock); relationName = generate_relation_name(tableRelationId); relationKind = relation->rd_rel->relkind; if (relationKind != RELKIND_RELATION && relationKind != RELKIND_FOREIGN_TABLE) { ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("%s is not a regular or foreign table", relationName))); } initStringInfo(&buffer); if (relationKind == RELKIND_RELATION) { appendStringInfo(&buffer, "CREATE TABLE %s (", relationName); } else { appendStringInfo(&buffer, "CREATE FOREIGN TABLE %s (", relationName); } /* * Iterate over the table's columns. If a particular column is not dropped * and is not inherited from another table, print the column's name and its * formatted type. */ tupleDescriptor = RelationGetDescr(relation); tupleConstraints = tupleDescriptor->constr; for (attributeIndex = 0; attributeIndex < tupleDescriptor->natts; attributeIndex++) { Form_pg_attribute attributeForm = tupleDescriptor->attrs[attributeIndex]; if (!attributeForm->attisdropped && attributeForm->attinhcount == 0) { const char *attributeName = NULL; const char *attributeTypeName = NULL; if (firstAttributePrinted) { appendStringInfoString(&buffer, ", "); } firstAttributePrinted = true; attributeName = NameStr(attributeForm->attname); appendStringInfo(&buffer, "%s ", quote_identifier(attributeName)); attributeTypeName = format_type_with_typemod(attributeForm->atttypid, attributeForm->atttypmod); appendStringInfoString(&buffer, attributeTypeName); /* if this column has a default value, append the default value */ if (attributeForm->atthasdef) { AttrDefault *defaultValueList = NULL; AttrDefault *defaultValue = NULL; Node *defaultNode = NULL; List *defaultContext = NULL; char *defaultString = NULL; Assert(tupleConstraints != NULL); defaultValueList = tupleConstraints->defval; Assert(defaultValueList != NULL); defaultValue = &(defaultValueList[defaultValueIndex]); defaultValueIndex++; Assert(defaultValue->adnum == (attributeIndex + 1)); Assert(defaultValueIndex <= tupleConstraints->num_defval); /* convert expression to node tree, and prepare deparse context */ defaultNode = (Node *) stringToNode(defaultValue->adbin); defaultContext = deparse_context_for(relationName, tableRelationId); /* deparse default value string */ defaultString = deparse_expression(defaultNode, defaultContext, false, false); appendStringInfo(&buffer, " DEFAULT %s", defaultString); } /* if this column has a not null constraint, append the constraint */ if (attributeForm->attnotnull) { appendStringInfoString(&buffer, " NOT NULL"); } } } /* * Now check if the table has any constraints. If it does, set the number of * check constraints here. Then iterate over all check constraints and print * them. */ if (tupleConstraints != NULL) { constraintCount = tupleConstraints->num_check; } for (constraintIndex = 0; constraintIndex < constraintCount; constraintIndex++) { ConstrCheck *checkConstraintList = tupleConstraints->check; ConstrCheck *checkConstraint = &(checkConstraintList[constraintIndex]); Node *checkNode = NULL; List *checkContext = NULL; char *checkString = NULL; /* if an attribute or constraint has been printed, format properly */ if (firstAttributePrinted || constraintIndex > 0) { appendStringInfoString(&buffer, ", "); } appendStringInfo(&buffer, "CONSTRAINT %s CHECK ", quote_identifier(checkConstraint->ccname)); /* convert expression to node tree, and prepare deparse context */ checkNode = (Node *) stringToNode(checkConstraint->ccbin); checkContext = deparse_context_for(relationName, tableRelationId); /* deparse check constraint string */ checkString = deparse_expression(checkNode, checkContext, false, false); appendStringInfoString(&buffer, checkString); } /* close create table's outer parentheses */ appendStringInfoString(&buffer, ")"); /* * If the relation is a foreign table, append the server name and options to * the create table statement. */ if (relationKind == RELKIND_FOREIGN_TABLE) { ForeignTable *foreignTable = GetForeignTable(tableRelationId); ForeignServer *foreignServer = GetForeignServer(foreignTable->serverid); char *serverName = foreignServer->servername; appendStringInfo(&buffer, " SERVER %s", quote_identifier(serverName)); AppendOptionListToString(&buffer, foreignTable->options); } relation_close(relation, AccessShareLock); return (buffer.data); }
void pgForeignTable::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane) { wxString constraint; if (!expandedKids) { expandedKids = true; pgSet *set = ExecuteSet( wxT("SELECT attname, format_type(t.oid,NULL) AS typname, attndims, atttypmod, nspname, attnotnull,\n") wxT(" (SELECT COUNT(1) from pg_type t2 WHERE t2.typname=t.typname) > 1 AS isdup\n") wxT(" FROM pg_attribute att\n") wxT(" JOIN pg_type t ON t.oid=atttypid\n") wxT(" JOIN pg_namespace nsp ON t.typnamespace=nsp.oid\n") wxT(" LEFT OUTER JOIN pg_type b ON t.typelem=b.oid\n") wxT(" WHERE att.attrelid=") + GetOidStr() + wxT("\n") wxT(" AND attnum>0\n") wxT(" ORDER by attnum")); if (set) { int anzvar = 0; while (!set->Eof()) { pgDatatype dt(set->GetVal(wxT("nspname")), set->GetVal(wxT("typname")), set->GetBool(wxT("isdup")), set->GetLong(wxT("attndims")) > 0, set->GetLong(wxT("atttypmod"))); constraint = set->GetBool(wxT("attnotnull")) ? wxT("NOT NULL") : wxT(""); if (anzvar++) { typesList += wxT(", "); quotedTypesList += wxT(",\n "); } typesList += set->GetVal(wxT("attname")) + wxT(" ") + dt.GetSchemaPrefix(GetDatabase()) + dt.FullName() + wxT(" ") + constraint; quotedTypesList += qtIdent(set->GetVal(wxT("attname"))) + wxT(" ") + dt.GetQuotedSchemaPrefix(GetDatabase()) + dt.QuotedFullName() + wxT(" ") + constraint; typesArray.Add(set->GetVal(wxT("attname"))); typesArray.Add(dt.GetSchemaPrefix(GetDatabase()) + dt.FullName()); typesArray.Add(constraint); set->MoveNext(); } delete set; } } if (properties) { CreateListColumns(properties); properties->AppendItem(_("Name"), GetName()); properties->AppendItem(_("OID"), GetOid()); properties->AppendItem(_("Owner"), GetOwner()); properties->AppendItem(_("Server"), GetForeignServer()); properties->AppendItem(_("Columns"), GetQuotedTypesList()); properties->AppendItem(_("Options"), GetOptionsList()); properties->AppendItem(_("Comment"), firstLineOnly(GetComment())); if (!GetLabels().IsEmpty()) { wxArrayString seclabels = GetProviderLabelArray(); if (seclabels.GetCount() > 0) { for (unsigned int index = 0 ; index < seclabels.GetCount() - 1 ; index += 2) { properties->AppendItem(seclabels.Item(index), seclabels.Item(index + 1)); } } } } }
/* * Get a PGconn which can be used to execute queries on the remote PostgreSQL * server with the user's authorization. A new connection is established * if we don't already have a suitable one, and a transaction is opened at * the right subtransaction nesting depth if we didn't do that already. * * will_prep_stmt must be true if caller intends to create any prepared * statements. Since those don't go away automatically at transaction end * (not even on error), we need this flag to cue manual cleanup. * * XXX Note that caching connections theoretically requires a mechanism to * detect change of FDW objects to invalidate already established connections. * We could manage that by watching for invalidation events on the relevant * syscaches. For the moment, though, it's not clear that this would really * be useful and not mere pedantry. We could not flush any active connections * mid-transaction anyway. */ PGconn * GetConnection(UserMapping *user, bool will_prep_stmt) { 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); /* allocate ConnectionHash in the cache context */ ctl.hcxt = CacheMemoryContext; ConnectionHash = hash_create("postgres_fdw connections", 8, &ctl, HASH_ELEM | HASH_BLOBS | 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 = user->umid; /* * 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) { ForeignServer *server = GetForeignServer(user->serverid); 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\" (user mapping oid %u, userid %u)", entry->conn, server->servername, user->umid, user->userid); } /* * 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; }