/* * 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); }
Datum gp_build_logical_index_info(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); FuncCallContext *funcctx; MemoryContext oldcontext; TupleDesc tupdesc; HeapTuple tuple; bool nulls[NUM_COLS]; LogicalIndexes *partsLI; if (SRF_IS_FIRSTCALL()) { /* create a function context */ funcctx = SRF_FIRSTCALL_INIT(); /* switch memory context for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* build tupdesc for result tuples */ tupdesc = CreateTemplateTupleDesc(NUM_COLS, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "logicalIndexId", OIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "nColumns", INT2OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "indexKeys", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "indIsUnique", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "indPred", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "indExprs", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 7, "partConsBin", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 8, "defaultLevels", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 9, "indType", INT2OID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); partsLI = (LogicalIndexes *)palloc(sizeof(LogicalIndexes)); funcctx->user_fctx = (void *) partsLI; /* do the actual work */ partsLI = BuildLogicalIndexInfo(relid); funcctx->user_fctx = (void *) partsLI; if (partsLI) funcctx->max_calls = partsLI->numLogicalIndexes; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); partsLI = (LogicalIndexes *)funcctx->user_fctx; if (funcctx->call_cntr < funcctx->max_calls) { /* fetch each tuple, and return */ Datum values[NUM_COLS]; Datum result; char *c; text *t; StringInfoData keys; int i; LogicalIndexInfo *li = partsLI->logicalIndexInfo[funcctx->call_cntr]; for (int i = 0; i < NUM_COLS; i++) nulls[i] = false; values[0] = ObjectIdGetDatum(li->logicalIndexOid); values[1] = Int16GetDatum(li->nColumns); initStringInfo(&keys); for (i = 0; i < li->nColumns; i++) appendStringInfo(&keys, "%d ",li->indexKeys[i]); t = cstring_to_text(keys.data); values[2] = PointerGetDatum(t); values[3] = BoolGetDatum(li->indIsUnique); if (li->indPred) { c = nodeToString(li->indPred); t = cstring_to_text(c); values[4] = PointerGetDatum(t); } else nulls[4] = true; if (li->indExprs) { c = nodeToString(li->indExprs); t = cstring_to_text(c); values[5] = PointerGetDatum(t); } else nulls[5] = true; if (li->partCons) { /* get the expr form -- for readability */ c = deparse_expression(li->partCons, deparse_context_for(get_rel_name(relid), relid), false, false); t = cstring_to_text(c); values[6] = PointerGetDatum(t); } else nulls[6] = true; if (li->defaultLevels) { c = nodeToString(li->defaultLevels); t = cstring_to_text(c); values[7] = PointerGetDatum(t); } else nulls[7] = true; values[8] = li->indType; nulls[8] = false; /* build tuple */ tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); /* make the tuple into a datum */ result = HeapTupleGetDatum(tuple); SRF_RETURN_NEXT(funcctx, result); } else { SRF_RETURN_DONE(funcctx); } }