/*---------------------------------------------------------------------- * test_ddl_deparse.c * Support functions for the test_ddl_deparse module * * Copyright (c) 2014-2025, PostgreSQL Global Development Group * * IDENTIFICATION * src/test/modules/test_ddl_deparse/test_ddl_deparse.c *---------------------------------------------------------------------- */ #include "postgres.h" #include "funcapi.h" #include "nodes/execnodes.h" #include "tcop/deparse_utility.h" #include "tcop/utility.h" #include "utils/builtins.h" PG_MODULE_MAGIC; PG_FUNCTION_INFO_V1(get_command_type); PG_FUNCTION_INFO_V1(get_command_tag); PG_FUNCTION_INFO_V1(get_altertable_subcmdinfo); /* * Return the textual representation of the struct type used to represent a * command in struct CollectedCommand format. */ Datum get_command_type(PG_FUNCTION_ARGS) { CollectedCommand *cmd = (CollectedCommand *) PG_GETARG_POINTER(0); const char *type; switch (cmd->type) { case SCT_Simple: type = "simple"; break; case SCT_AlterTable: type = "alter table"; break; case SCT_Grant: type = "grant"; break; case SCT_AlterOpFamily: type = "alter operator family"; break; case SCT_AlterDefaultPrivileges: type = "alter default privileges"; break; case SCT_CreateOpClass: type = "create operator class"; break; case SCT_AlterTSConfig: type = "alter text search configuration"; break; default: type = "unknown command type"; break; } PG_RETURN_TEXT_P(cstring_to_text(type)); } /* * Return the command tag corresponding to a parse node contained in a * CollectedCommand struct. */ Datum get_command_tag(PG_FUNCTION_ARGS) { CollectedCommand *cmd = (CollectedCommand *) PG_GETARG_POINTER(0); if (!cmd->parsetree) PG_RETURN_NULL(); PG_RETURN_TEXT_P(cstring_to_text(CreateCommandName(cmd->parsetree))); } /* * Return a text array representation of the subcommands of an ALTER TABLE * command. */ Datum get_altertable_subcmdinfo(PG_FUNCTION_ARGS) { CollectedCommand *cmd = (CollectedCommand *) PG_GETARG_POINTER(0); ListCell *cell; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; if (cmd->type != SCT_AlterTable) elog(ERROR, "command is not ALTER TABLE"); InitMaterializedSRF(fcinfo, 0); if (cmd->d.alterTable.subcmds == NIL) elog(ERROR, "empty alter table subcommand list"); foreach(cell, cmd->d.alterTable.subcmds) { CollectedATSubcmd *sub = lfirst(cell); AlterTableCmd *subcmd = castNode(AlterTableCmd, sub->parsetree); const char *strtype = "unrecognized"; Datum values[2]; bool nulls[2]; memset(values, 0, sizeof(values)); memset(nulls, 0, sizeof(nulls)); switch (subcmd->subtype) { case AT_AddColumn: strtype = "ADD COLUMN"; break; case AT_AddColumnToView: strtype = "ADD COLUMN TO VIEW"; break; case AT_ColumnDefault: strtype = "ALTER COLUMN SET DEFAULT"; break; case AT_CookedColumnDefault: strtype = "ALTER COLUMN SET DEFAULT (precooked)"; break; case AT_DropNotNull: strtype = "DROP NOT NULL"; break; case AT_SetNotNull: strtype = "SET NOT NULL"; break; case AT_SetExpression: strtype = "SET EXPRESSION"; break; case AT_DropExpression: strtype = "DROP EXPRESSION"; break; case AT_SetStatistics: strtype = "SET STATS"; break; case AT_SetOptions: strtype = "SET OPTIONS"; break; case AT_ResetOptions: strtype = "RESET OPTIONS"; break; case AT_SetStorage: strtype = "SET STORAGE"; break; case AT_SetCompression: strtype = "SET COMPRESSION"; break; case AT_DropColumn: strtype = "DROP COLUMN"; break; case AT_AddIndex: strtype = "ADD INDEX"; break; case AT_ReAddIndex: strtype = "(re) ADD INDEX"; break; case AT_AddConstraint: strtype = "ADD CONSTRAINT"; break; case AT_ReAddConstraint: strtype = "(re) ADD CONSTRAINT"; break; case AT_ReAddDomainConstraint: strtype = "(re) ADD DOMAIN CONSTRAINT"; break; case AT_AlterConstraint: strtype = "ALTER CONSTRAINT"; break; case AT_ValidateConstraint: strtype = "VALIDATE CONSTRAINT"; break; case AT_AddIndexConstraint: strtype = "ADD CONSTRAINT (using index)"; break; case AT_DropConstraint: strtype = "DROP CONSTRAINT"; break; case AT_ReAddComment: strtype = "(re) ADD COMMENT"; break; case AT_AlterColumnType: strtype = "ALTER COLUMN SET TYPE"; break; case AT_AlterColumnGenericOptions: strtype = "ALTER COLUMN SET OPTIONS"; break; case AT_ChangeOwner: strtype = "CHANGE OWNER"; break; case AT_ClusterOn: strtype = "CLUSTER"; break; case AT_DropCluster: strtype = "DROP CLUSTER"; break; case AT_SetLogged: strtype = "SET LOGGED"; break; case AT_SetUnLogged: strtype = "SET UNLOGGED"; break; case AT_DropOids: strtype = "DROP OIDS"; break; case AT_SetAccessMethod: strtype = "SET ACCESS METHOD"; break; case AT_SetTableSpace: strtype = "SET TABLESPACE"; break; case AT_SetRelOptions: strtype = "SET RELOPTIONS"; break; case AT_ResetRelOptions: strtype = "RESET RELOPTIONS"; break; case AT_ReplaceRelOptions: strtype = "REPLACE RELOPTIONS"; break; case AT_EnableTrig: strtype = "ENABLE TRIGGER"; break; case AT_EnableAlwaysTrig: strtype = "ENABLE TRIGGER (always)"; break; case AT_EnableReplicaTrig: strtype = "ENABLE TRIGGER (replica)"; break; case AT_DisableTrig: strtype = "DISABLE TRIGGER"; break; case AT_EnableTrigAll: strtype = "ENABLE TRIGGER (all)"; break; case AT_DisableTrigAll: strtype = "DISABLE TRIGGER (all)"; break; case AT_EnableTrigUser: strtype = "ENABLE TRIGGER (user)"; break; case AT_DisableTrigUser: strtype = "DISABLE TRIGGER (user)"; break; case AT_EnableRule: strtype = "ENABLE RULE"; break; case AT_EnableAlwaysRule: strtype = "ENABLE RULE (always)"; break; case AT_EnableReplicaRule: strtype = "ENABLE RULE (replica)"; break; case AT_DisableRule: strtype = "DISABLE RULE"; break; case AT_AddInherit: strtype = "ADD INHERIT"; break; case AT_DropInherit: strtype = "DROP INHERIT"; break; case AT_AddOf: strtype = "OF"; break; case AT_DropOf: strtype = "NOT OF"; break; case AT_ReplicaIdentity: strtype = "REPLICA IDENTITY"; break; case AT_EnableRowSecurity: strtype = "ENABLE ROW SECURITY"; break; case AT_DisableRowSecurity: strtype = "DISABLE ROW SECURITY"; break; case AT_ForceRowSecurity: strtype = "FORCE ROW SECURITY"; break; case AT_NoForceRowSecurity: strtype = "NO FORCE ROW SECURITY"; break; case AT_GenericOptions: strtype = "SET OPTIONS"; break; case AT_DetachPartition: strtype = "DETACH PARTITION"; break; case AT_AttachPartition: strtype = "ATTACH PARTITION"; break; case AT_DetachPartitionFinalize: strtype = "DETACH PARTITION ... FINALIZE"; break; case AT_AddIdentity: strtype = "ADD IDENTITY"; break; case AT_SetIdentity: strtype = "SET IDENTITY"; break; case AT_DropIdentity: strtype = "DROP IDENTITY"; break; case AT_ReAddStatistics: strtype = "(re) ADD STATS"; break; } if (subcmd->recurse) values[0] = CStringGetTextDatum(psprintf("%s (and recurse)", strtype)); else values[0] = CStringGetTextDatum(strtype); if (OidIsValid(sub->address.objectId)) { char *objdesc; objdesc = getObjectDescription((const ObjectAddress *) &sub->address, false); values[1] = CStringGetTextDatum(objdesc); } else nulls[1] = true; tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); } return (Datum) 0; }