/*------------------------------------------------------------------------- * * qualify_function_stmt.c * Functions specialized in fully qualifying all function statements. These * functions are dispatched from qualify.c * * Fully qualifying function statements consists of adding the schema name * to the subject of the function and types as well as any other branch of * the parsetree. * * Goal would be that the deparser functions for these statements can * serialize the statement without any external lookups. * * Copyright (c), Citus Data, Inc. * *------------------------------------------------------------------------- */ #include "postgres.h" #include "access/htup_details.h" #include "catalog/namespace.h" #include "catalog/pg_proc.h" #include "distributed/deparser.h" #include "distributed/version_compat.h" #include "parser/parse_func.h" #include "utils/lsyscache.h" #include "utils/syscache.h" /* forward declaration for qualify functions */ static void QualifyFunction(ObjectWithArgs *func, ObjectType type); static void QualifyFunctionSchemaName(ObjectWithArgs *func, ObjectType type); /* AssertObjectTypeIsFunctionType asserts we aren't receiving something we shouldn't */ void AssertObjectTypeIsFunctional(ObjectType type) { Assert(type == OBJECT_AGGREGATE || type == OBJECT_FUNCTION || type == OBJECT_PROCEDURE || type == OBJECT_ROUTINE); } /* * QualifyAlterFunctionStmt transforms a * ALTER {AGGREGATE|FUNCTION|PROCEDURE} .. * statement in place and makes all (supported) statements fully qualified. * * Note that not all queries of this form are valid AlterFunctionStmt * (e.g. ALTER FUNCTION .. RENAME .. queries are RenameStmt ) */ void QualifyAlterFunctionStmt(Node *node) { AlterFunctionStmt *stmt = castNode(AlterFunctionStmt, node); AssertObjectTypeIsFunctional(stmt->objtype); QualifyFunction(stmt->func, stmt->objtype); } /* * QualifyRenameFunctionStmt transforms a * ALTER {AGGREGATE|FUNCTION|PROCEDURE} .. RENAME TO .. * statement in place and makes the function name fully qualified. */ void QualifyRenameFunctionStmt(Node *node) { RenameStmt *stmt = castNode(RenameStmt, node); AssertObjectTypeIsFunctional(stmt->renameType); QualifyFunction(castNode(ObjectWithArgs, stmt->object), stmt->renameType); } /* * QualifyAlterFunctionSchemaStmt transforms a * ALTER {AGGREGATE|FUNCTION|PROCEDURE} .. SET SCHEMA .. * statement in place and makes the function name fully qualified. */ void QualifyAlterFunctionSchemaStmt(Node *node) { AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node); AssertObjectTypeIsFunctional(stmt->objectType); QualifyFunction(castNode(ObjectWithArgs, stmt->object), stmt->objectType); } /* * QualifyAlterFunctionOwnerStmt transforms a * ALTER {AGGREGATE|FUNCTION|PROCEDURE} .. OWNER TO .. * statement in place and makes the function name fully qualified. */ void QualifyAlterFunctionOwnerStmt(Node *node) { AlterOwnerStmt *stmt = castNode(AlterOwnerStmt, node); AssertObjectTypeIsFunctional(stmt->objectType); QualifyFunction(castNode(ObjectWithArgs, stmt->object), stmt->objectType); } /* * QualifyAlterFunctionDependsStmt transforms a * ALTER {FUNCTION|PROCEDURE} .. DEPENDS ON EXTENSION .. * statement in place and makes the function name fully qualified. */ void QualifyAlterFunctionDependsStmt(Node *node) { AlterObjectDependsStmt *stmt = castNode(AlterObjectDependsStmt, node); AssertObjectTypeIsFunctional(stmt->objectType); QualifyFunction(castNode(ObjectWithArgs, stmt->object), stmt->objectType); } /* * QualifyFunction transforms a function in place and makes its name fully qualified. */ void QualifyFunction(ObjectWithArgs *func, ObjectType type) { char *functionName = NULL; char *schemaName = NULL; /* check if the function name is already qualified */ DeconstructQualifiedName(func->objname, &schemaName, &functionName); /* do a lookup for the schema name if the statement does not include one */ if (schemaName == NULL) { QualifyFunctionSchemaName(func, type); } } /* * QualifyFunction transforms a function in place using a catalog lookup for its schema name to make it fully qualified. */ void QualifyFunctionSchemaName(ObjectWithArgs *func, ObjectType type) { char *schemaName = NULL; char *functionName = NULL; Oid funcid = LookupFuncWithArgs(type, func, true); HeapTuple proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); /* * We can not qualify the function if the catalogs do not have any records. * * e.g. DROP FUNC IF EXISTS non_existent_func() do not result in a valid heap tuple */ if (HeapTupleIsValid(proctup)) { Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup); schemaName = get_namespace_name(procform->pronamespace); functionName = NameStr(procform->proname); functionName = pstrdup(functionName); /* we release the tuple before used */ ReleaseSysCache(proctup); /* update the function using the schema name */ func->objname = list_make2(makeString(schemaName), makeString(functionName)); } }