/*------------------------------------------------------------------------- * * deparse_sequence_stmts.c * * All routines to deparse sequence statements. * This file contains all entry points specific for sequence statement * deparsing * * Copyright (c), Citus Data, Inc. * *------------------------------------------------------------------------- */ #include "postgres.h" #include "catalog/namespace.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/lsyscache.h" #include "distributed/deparser.h" #include "distributed/version_compat.h" /* forward declaration for deparse functions */ static void AppendDropSequenceStmt(StringInfo buf, DropStmt *stmt); static void AppendSequenceNameList(StringInfo buf, List *objects, ObjectType objtype); static void AppendRenameSequenceStmt(StringInfo buf, RenameStmt *stmt); static void AppendAlterSequenceSchemaStmt(StringInfo buf, AlterObjectSchemaStmt *stmt); static void AppendAlterSequenceOwnerStmt(StringInfo buf, AlterTableStmt *stmt); static void AppendAlterSequencePersistenceStmt(StringInfo buf, AlterTableStmt *stmt); static void AppendGrantOnSequenceStmt(StringInfo buf, GrantStmt *stmt); static void AppendGrantOnSequenceSequences(StringInfo buf, GrantStmt *stmt); /* * DeparseDropSequenceStmt builds and returns a string representing the DropStmt */ char * DeparseDropSequenceStmt(Node *node) { DropStmt *stmt = castNode(DropStmt, node); StringInfoData str = { 0 }; initStringInfo(&str); Assert(stmt->removeType == OBJECT_SEQUENCE); AppendDropSequenceStmt(&str, stmt); return str.data; } /* * AppendDropSequenceStmt appends a string representing the DropStmt to a buffer */ static void AppendDropSequenceStmt(StringInfo buf, DropStmt *stmt) { appendStringInfoString(buf, "DROP SEQUENCE "); if (stmt->missing_ok) { appendStringInfoString(buf, "IF EXISTS "); } AppendSequenceNameList(buf, stmt->objects, stmt->removeType); if (stmt->behavior == DROP_CASCADE) { appendStringInfoString(buf, " CASCADE"); } appendStringInfoString(buf, ";"); } /* * AppendSequenceNameList appends a string representing the list of sequence names to a buffer */ static void AppendSequenceNameList(StringInfo buf, List *objects, ObjectType objtype) { ListCell *objectCell = NULL; foreach(objectCell, objects) { if (objectCell != list_head(objects)) { appendStringInfo(buf, ", "); } RangeVar *seq = makeRangeVarFromNameList((List *) lfirst(objectCell)); char *qualifiedSequenceName = quote_qualified_identifier(seq->schemaname, seq->relname); appendStringInfoString(buf, qualifiedSequenceName); } } /* * DeparseRenameSequenceStmt builds and returns a string representing the RenameStmt */ char * DeparseRenameSequenceStmt(Node *node) { RenameStmt *stmt = castNode(RenameStmt, node); StringInfoData str = { 0 }; initStringInfo(&str); Assert(stmt->renameType == OBJECT_SEQUENCE); AppendRenameSequenceStmt(&str, stmt); return str.data; } /* * AppendRenameSequenceStmt appends a string representing the RenameStmt to a buffer */ static void AppendRenameSequenceStmt(StringInfo buf, RenameStmt *stmt) { RangeVar *seq = stmt->relation; char *qualifiedSequenceName = quote_qualified_identifier(seq->schemaname, seq->relname); appendStringInfoString(buf, "ALTER SEQUENCE "); if (stmt->missing_ok) { appendStringInfoString(buf, "IF EXISTS "); } appendStringInfoString(buf, qualifiedSequenceName); appendStringInfo(buf, " RENAME TO %s", quote_identifier(stmt->newname)); } /* * DeparseAlterSequenceSchemaStmt builds and returns a string representing the AlterObjectSchemaStmt */ char * DeparseAlterSequenceSchemaStmt(Node *node) { AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node); StringInfoData str = { 0 }; initStringInfo(&str); Assert(stmt->objectType == OBJECT_SEQUENCE); AppendAlterSequenceSchemaStmt(&str, stmt); return str.data; } /* * AppendAlterSequenceSchemaStmt appends a string representing the AlterObjectSchemaStmt to a buffer */ static void AppendAlterSequenceSchemaStmt(StringInfo buf, AlterObjectSchemaStmt *stmt) { RangeVar *seq = stmt->relation; char *qualifiedSequenceName = quote_qualified_identifier(seq->schemaname, seq->relname); appendStringInfoString(buf, "ALTER SEQUENCE "); if (stmt->missing_ok) { appendStringInfoString(buf, "IF EXISTS "); } appendStringInfoString(buf, qualifiedSequenceName); appendStringInfo(buf, " SET SCHEMA %s;", quote_identifier(stmt->newschema)); } /* * DeparseAlterSequenceOwnerStmt builds and returns a string representing the AlterTableStmt * consisting of changing the owner of a sequence */ char * DeparseAlterSequenceOwnerStmt(Node *node) { AlterTableStmt *stmt = castNode(AlterTableStmt, node); StringInfoData str = { 0 }; initStringInfo(&str); Assert(stmt->objtype == OBJECT_SEQUENCE); AppendAlterSequenceOwnerStmt(&str, stmt); return str.data; } /* * AppendAlterSequenceOwnerStmt appends a string representing the AlterTableStmt to a buffer * consisting of changing the owner of a sequence */ static void AppendAlterSequenceOwnerStmt(StringInfo buf, AlterTableStmt *stmt) { Assert(stmt->objtype == OBJECT_SEQUENCE); RangeVar *seq = stmt->relation; char *qualifiedSequenceName = quote_qualified_identifier(seq->schemaname, seq->relname); appendStringInfoString(buf, "ALTER SEQUENCE "); if (stmt->missing_ok) { appendStringInfoString(buf, "IF EXISTS "); } appendStringInfoString(buf, qualifiedSequenceName); ListCell *cmdCell = NULL; foreach(cmdCell, stmt->cmds) { if (cmdCell != list_head(stmt->cmds)) { /* * normally we shouldn't ever reach this * because we enter this function after making sure we have only * one subcommand of the type AT_ChangeOwner */ ereport(ERROR, (errmsg("More than one subcommand is not supported " "for ALTER SEQUENCE"))); } AlterTableCmd *alterTableCmd = castNode(AlterTableCmd, lfirst(cmdCell)); switch (alterTableCmd->subtype) { case AT_ChangeOwner: { appendStringInfo(buf, " OWNER TO %s;", get_rolespec_name( alterTableCmd->newowner)); break; } default: { /* * normally we shouldn't ever reach this * because we enter this function after making sure this stmt is of the form * ALTER SEQUENCE .. OWNER TO .. */ ereport(ERROR, (errmsg("unsupported subtype for alter sequence command"), errdetail("sub command type: %d", alterTableCmd->subtype))); } } } } /* * DeparseAlterSequencePersistenceStmt builds and returns a string representing * the AlterTableStmt consisting of changing the persistence of a sequence */ char * DeparseAlterSequencePersistenceStmt(Node *node) { AlterTableStmt *stmt = castNode(AlterTableStmt, node); StringInfoData str = { 0 }; initStringInfo(&str); Assert(stmt->objtype == OBJECT_SEQUENCE); AppendAlterSequencePersistenceStmt(&str, stmt); return str.data; } /* * AppendAlterSequencePersistenceStmt appends a string representing the * AlterTableStmt to a buffer consisting of changing the persistence of a sequence */ static void AppendAlterSequencePersistenceStmt(StringInfo buf, AlterTableStmt *stmt) { Assert(stmt->objtype == OBJECT_SEQUENCE); RangeVar *seq = stmt->relation; char *qualifiedSequenceName = quote_qualified_identifier(seq->schemaname, seq->relname); appendStringInfoString(buf, "ALTER SEQUENCE "); if (stmt->missing_ok) { appendStringInfoString(buf, "IF EXISTS "); } appendStringInfoString(buf, qualifiedSequenceName); ListCell *cmdCell = NULL; foreach(cmdCell, stmt->cmds) { if (cmdCell != list_head(stmt->cmds)) { /* * As of PG15, we cannot reach this code because ALTER SEQUENCE * is only supported for a single sequence. Still, let's be * defensive for future PG changes */ ereport(ERROR, (errmsg("More than one subcommand is not supported " "for ALTER SEQUENCE"))); } AlterTableCmd *alterTableCmd = castNode(AlterTableCmd, lfirst(cmdCell)); switch (alterTableCmd->subtype) { case AT_SetLogged: { appendStringInfoString(buf, " SET LOGGED;"); break; } case AT_SetUnLogged: { appendStringInfoString(buf, " SET UNLOGGED;"); break; } default: { /* * normally we shouldn't ever reach this * because we enter this function after making sure this stmt is of the form * ALTER SEQUENCE .. SET LOGGED/UNLOGGED */ ereport(ERROR, (errmsg("unsupported subtype for alter sequence command"), errdetail("sub command type: %d", alterTableCmd->subtype))); } } } } /* * DeparseGrantOnSequenceStmt builds and returns a string representing the GrantOnSequenceStmt */ char * DeparseGrantOnSequenceStmt(Node *node) { GrantStmt *stmt = castNode(GrantStmt, node); Assert(stmt->objtype == OBJECT_SEQUENCE); StringInfoData str = { 0 }; initStringInfo(&str); AppendGrantOnSequenceStmt(&str, stmt); return str.data; } /* * AppendGrantOnSequenceStmt builds and returns an SQL command representing a * GRANT .. ON SEQUENCE command from given GrantStmt object. */ static void AppendGrantOnSequenceStmt(StringInfo buf, GrantStmt *stmt) { Assert(stmt->objtype == OBJECT_SEQUENCE); if (stmt->targtype == ACL_TARGET_ALL_IN_SCHEMA) { /* * Normally we shouldn't reach this * We deparse a GrantStmt with OBJECT_SEQUENCE after setting targtype * to ACL_TARGET_OBJECT */ elog(ERROR, "GRANT .. ALL SEQUENCES IN SCHEMA is not supported for formatting."); } AppendGrantSharedPrefix(buf, stmt); AppendGrantOnSequenceSequences(buf, stmt); AppendGrantSharedSuffix(buf, stmt); } /* * AppendGrantOnSequenceSequences appends the sequence names along with their arguments * to the given StringInfo from the given GrantStmt */ static void AppendGrantOnSequenceSequences(StringInfo buf, GrantStmt *stmt) { Assert(stmt->objtype == OBJECT_SEQUENCE); appendStringInfoString(buf, " ON SEQUENCE "); ListCell *cell = NULL; foreach(cell, stmt->objects) { /* * GrantOnSequence statement keeps its objects (sequences) as * a list of RangeVar-s */ RangeVar *sequence = (RangeVar *) lfirst(cell); /* * We have qualified the statement beforehand */ appendStringInfoString(buf, quote_qualified_identifier(sequence->schemaname, sequence->relname)); if (cell != list_tail(stmt->objects)) { appendStringInfoString(buf, ", "); } } }