Ejemplo n.º 1
0
/* ------------------------------------------------------------
 *
 * Routines copied from core PostgreSQL implementation
 *
 * ------------------------------------------------------------
 */
void
show_scan_qual(List *qual, const char *qlabel,
               PlanState *planstate, List *ancestors,
               ExplainState *es)
{
	bool        useprefix;
	Node	   *node;
	List       *context;
	char       *exprstr;

	useprefix = (IsA(planstate->plan, SubqueryScan) || es->verbose);

	/* No work if empty qual */
	if (qual == NIL)
		return;

	/* Convert AND list to explicit AND */
	node = (Node *) make_ands_explicit(qual);

	/* Set up deparsing context */
	context = deparse_context_for_planstate((Node *) planstate,
											ancestors,
											es->rtable,
											es->rtable_names);

	/* Deparse the expression */
	exprstr = deparse_expression(node, context, useprefix, false);

	/* And add to es->str */
	ExplainPropertyText(qlabel, exprstr, es);
}
Ejemplo n.º 2
0
/*
 * 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);
}
Ejemplo n.º 3
0
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);
	}
}