0005-POC-for-autogenerating-alter-table-subcommands-for-d.patch
text/x-patch
Filename: 0005-POC-for-autogenerating-alter-table-subcommands-for-d.patch
Type: text/x-patch
Part: 3
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0005
Subject: POC for autogenerating "alter table" subcommands for ddl replication.
| File | + | − |
|---|---|---|
| src/backend/nodes/ddldeparsefuncs.c | 6 | 368 |
| src/backend/nodes/gen_node_support.pl | 238 | 3 |
| src/include/nodes/parsenodes.h | 138 | 61 |
From d6649bb33c749bc60099acae303a80b1edd6f62e Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 27 Jun 2023 14:45:27 +0530
Subject: [PATCH 5/5] POC for autogenerating "alter table" subcommands for ddl
replication.
POC for autogenerating "alter table" subcommands for ddl replication.
The patch does the following:
a) Reads AlterTableType enum and the members of AlterTableType enum.
b) Each of the AlterTableType enum field has the following common code,
case Enum member:
pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
new_jsonb_VA(state, variable_count, "fmt", jbvString, variable_field);
pushJsonbValue(&state, WJB_END_OBJECT, NULL);
break;
In the above variable_count and variable_field values can be different.
These values can be annotated like below:
AT_ForceRowSecurity pg_node_attr(deparse_as(1:FORCE ROW LEVEL SECURITY))
Handles each of the AlterTableType enum with one of the below:
1) Generate the variable parameter case specified like:
When
"AT_ForceRowSecurity pg_node_attr(deparse_as(1:FORCE ROW LEVEL SECURITY)),"
is specified. Generate the following code:
case AT_ForceRowSecurity:
pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
new_jsonb_VA(state, 1, "fmt", jbvString, "FORCE ROW LEVEL SECURITY");
pushJsonbValue(&state, WJB_END_OBJECT, NULL);
break;
When
"AT_SetLogged pg_node_attr(deparse_as(2:SET LOGGED:type:set logged)),"
is specified. Generate the following code:
case AT_SetLogged:
pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
new_jsonb_VA(state, 2,
"fmt", jbvString, "SET LOGGED",
"type", jbvString, "set logged");
pushJsonbValue(&state, WJB_END_OBJECT, NULL);
break;
soon for more number of variable parameters.
2) If there is no annotation specified, just add "case" and "break" statement like:
case AT_ReAddStatistics:
/* Subtypes used for internal operations; nothing to do here */
break;
3) If deparse_ignore annotation is specified, do not generate any code for this.
---
src/backend/nodes/ddldeparsefuncs.c | 374 +-------------------------
src/backend/nodes/gen_node_support.pl | 241 ++++++++++++++++-
src/include/nodes/parsenodes.h | 199 +++++++++-----
3 files changed, 382 insertions(+), 432 deletions(-)
diff --git a/src/backend/nodes/ddldeparsefuncs.c b/src/backend/nodes/ddldeparsefuncs.c
index bdded259c7..12d3050bdc 100644
--- a/src/backend/nodes/ddldeparsefuncs.c
+++ b/src/backend/nodes/ddldeparsefuncs.c
@@ -250,6 +250,8 @@ deparse_drop_table(const char *objidentity, const char *objecttype,
return JsonbToCString(&str, &jsonb->root, JSONB_ESTIMATED_LEN);
}
+#define GET_ROLE_SPEC_DDL_ALTER_TBL get_rolespec_name(subcmd->newowner)
+
/*
* Deparse all the collected subcommands and return jsonb string representing
* the alter command.
@@ -331,6 +333,7 @@ deparse_AlterTableStmt(CollectedCommand *cmd)
{
CollectedATSubcmd *sub = (CollectedATSubcmd *) lfirst(cell);
AlterTableCmd *subcmd = (AlterTableCmd *) sub->parsetree;
+ char *name = subcmd->name;
Assert(IsA(subcmd, AlterTableCmd));
@@ -442,15 +445,6 @@ deparse_AlterTableStmt(CollectedCommand *cmd)
relation_close(idx, AccessShareLock);
break;
}
- case AT_ReAddIndex:
- case AT_ReAddConstraint:
- case AT_ReAddDomainConstraint:
- case AT_ReAddComment:
- case AT_ReplaceRelOptions:
- case AT_CheckNotNull:
- case AT_ReAddStatistics:
- /* Subtypes used for internal operations; nothing to do here */
- break;
case AT_ColumnDefault:
if (subcmd->def == NULL)
@@ -501,56 +495,6 @@ deparse_AlterTableStmt(CollectedCommand *cmd)
break;
- case AT_DropNotNull:
-
- /*
- * Syntax: ALTER COLUMN %{column}I DROP NOT NULL
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString,
- "ALTER COLUMN %{column}I DROP NOT NULL",
- "type", jbvString, "drop not null",
- "column", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_ForceRowSecurity:
-
- /*
- * Syntax: FORCE ROW LEVEL SECURITY
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 1, "fmt", jbvString,
- "FORCE ROW LEVEL SECURITY");
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_NoForceRowSecurity:
-
- /*
- * Syntax: NO FORCE ROW LEVEL SECURITY
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 1, "fmt", jbvString,
- "NO FORCE ROW LEVEL SECURITY");
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_SetNotNull:
-
- /*
- * Syntax: ALTER COLUMN %{column}I SET NOT NULL
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString,
- "ALTER COLUMN %{column}I SET NOT NULL",
- "type", jbvString, "set not null",
- "column", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
case AT_DropExpression:
{
StringInfoData fmtSub;
@@ -783,20 +727,6 @@ deparse_AlterTableStmt(CollectedCommand *cmd)
}
break;
- case AT_ValidateConstraint:
-
- /*
- * Syntax: VALIDATE CONSTRAINT %{constraint}I
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString,
- "VALIDATE CONSTRAINT %{constraint}I",
- "type", jbvString, "validate constraint",
- "constraint", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
case AT_DropConstraint:
{
StringInfoData fmtSub;
@@ -908,109 +838,6 @@ deparse_AlterTableStmt(CollectedCommand *cmd)
}
break;
- case AT_ChangeOwner:
-
- /*
- * Syntax: OWNER TO %{owner}I
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString, "OWNER TO %{owner}I",
- "type", jbvString, "change owner",
- "owner", jbvString,
- get_rolespec_name(subcmd->newowner));
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_ClusterOn:
-
- /*
- * Syntax: CLUSTER ON %{index}I
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString, "CLUSTER ON %{index}I",
- "type", jbvString, "cluster on",
- "index", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
-
- case AT_DropCluster:
-
- /*
- * Syntax: SET WITHOUT CLUSTER
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 2,
- "fmt", jbvString, "SET WITHOUT CLUSTER",
- "type", jbvString, "set without cluster");
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_SetLogged:
-
- /*
- * Syntax: SET LOGGED
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 2,
- "fmt", jbvString, "SET LOGGED",
- "type", jbvString, "set logged");
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_SetUnLogged:
-
- /*
- * Syntax: SET UNLOGGED
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 2,
- "fmt", jbvString, "SET UNLOGGED",
- "type", jbvString, "set unlogged");
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_DropOids:
-
- /*
- * Syntax: SET WITHOUT OIDS
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 2,
- "fmt", jbvString, "SET WITHOUT OIDS",
- "type", jbvString, "set without oids");
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_SetAccessMethod:
-
- /*
- * Syntax: SET ACCESS METHOD %{access_method}I
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString,
- "SET ACCESS METHOD %{access_method}I",
- "type", jbvString, "set access method",
- "access_method", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_SetTableSpace:
-
- /*
- * Syntax: SET TABLESPACE %{tablespace}I
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString, "SET TABLESPACE %{tablespace}I",
- "type", jbvString, "set tablespace",
- "tablespace", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
case AT_SetRelOptions:
case AT_ResetRelOptions:
@@ -1020,160 +847,6 @@ deparse_AlterTableStmt(CollectedCommand *cmd)
deparse_RelSetOptions_toJsonb(state, subcmd);
break;
- case AT_EnableTrig:
-
- /*
- * Syntax: ENABLE TRIGGER %{trigger}I
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString, "ENABLE TRIGGER %{trigger}I",
- "type", jbvString, "enable trigger",
- "trigger", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_EnableAlwaysTrig:
-
- /*
- * Syntax: ENABLE ALWAYS TRIGGER %{trigger}I
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString,
- "ENABLE ALWAYS TRIGGER %{trigger}I",
- "type", jbvString, "enable always trigger",
- "trigger", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_EnableReplicaTrig:
-
- /*
- * Syntax: ENABLE REPLICA TRIGGER %{trigger}I
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString,
- "ENABLE REPLICA TRIGGER %{trigger}I",
- "type", jbvString, "enable replica trigger",
- "trigger", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_DisableTrig:
-
- /*
- * Syntax: DISABLE TRIGGER %{trigger}I
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString, "DISABLE TRIGGER %{trigger}I",
- "type", jbvString, "disable trigger",
- "trigger", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_EnableTrigAll:
-
- /*
- * Syntax: ENABLE TRIGGER ALL
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 2,
- "fmt", jbvString, "ENABLE TRIGGER ALL",
- "type", jbvString, "enable trigger all");
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_DisableTrigAll:
-
- /*
- * Syntax: DISABLE TRIGGER ALL
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 2,
- "fmt", jbvString, "DISABLE TRIGGER ALL",
- "type", jbvString, "disable trigger all");
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_EnableTrigUser:
-
- /*
- * Syntax: ENABLE TRIGGER USER
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 2,
- "fmt", jbvString, "ENABLE TRIGGER USER",
- "type", jbvString, "enable trigger user");
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_DisableTrigUser:
-
- /*
- * Syntax: DISABLE TRIGGER USER
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 2,
- "fmt", jbvString, "DISABLE TRIGGER USER",
- "type", jbvString, "disable trigger user");
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_EnableRule:
-
- /*
- * Syntax: ENABLE RULE %{rule}I
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString, "ENABLE RULE %{rule}I",
- "type", jbvString, "enable rule",
- "rule", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_EnableAlwaysRule:
-
- /*
- * Syntax: ENABLE ALWAYS RULE %{rule}I
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString, "ENABLE ALWAYS RULE %{rule}I",
- "type", jbvString, "enable always rule",
- "rule", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_EnableReplicaRule:
-
- /*
- * Syntax: ENABLE REPLICA RULE %{rule}I
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString, "ENABLE REPLICA RULE %{rule}I",
- "type", jbvString, "enable replica rule",
- "rule", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_DisableRule:
-
- /*
- * Syntax: DISABLE RULE %{rule}I
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 3,
- "fmt", jbvString, "DISABLE RULE %{rule}I",
- "type", jbvString, "disable rule",
- "rule", jbvString, subcmd->name);
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
case AT_AddInherit:
/*
@@ -1215,18 +888,6 @@ deparse_AlterTableStmt(CollectedCommand *cmd)
pushJsonbValue(&state, WJB_END_OBJECT, NULL);
break;
- case AT_DropOf:
-
- /*
- * Syntax: NOT OF
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 2,
- "fmt", jbvString, "NOT OF",
- "type", jbvString, "not of");
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
case AT_ReplicaIdentity:
/*
@@ -1259,32 +920,6 @@ deparse_AlterTableStmt(CollectedCommand *cmd)
pushJsonbValue(&state, WJB_END_OBJECT, NULL);
break;
- case AT_EnableRowSecurity:
-
- /*
- * Syntax: ENABLE ROW LEVEL SECURITY
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 2,
- "fmt", jbvString,
- "ENABLE ROW LEVEL SECURITY",
- "type", jbvString, "enable row security");
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
- case AT_DisableRowSecurity:
-
- /*
- * Syntax: DISABLE ROW LEVEL SECURITY
- */
- pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
- new_jsonb_VA(state, 2,
- "fmt", jbvString,
- "DISABLE ROW LEVEL SECURITY",
- "type", jbvString, "disable row security");
- pushJsonbValue(&state, WJB_END_OBJECT, NULL);
- break;
-
case AT_AttachPartition:
{
StringInfoData fmtSub;
@@ -1509,6 +1144,9 @@ deparse_AlterTableStmt(CollectedCommand *cmd)
pushJsonbValue(&state, WJB_END_OBJECT, NULL);
break;
}
+
+ #include "ddldeparsefuncs_alter.switch.c"
+
default:
elog(WARNING, "unsupported alter table subtype %d",
subcmd->subtype);
diff --git a/src/backend/nodes/gen_node_support.pl b/src/backend/nodes/gen_node_support.pl
index 04757b79fb..3c63905361 100644
--- a/src/backend/nodes/gen_node_support.pl
+++ b/src/backend/nodes/gen_node_support.pl
@@ -117,6 +117,8 @@ my @node_types = qw(Node);
# collect info for each node type
my %node_type_info;
+my %enum_type_info;
+
# node types we don't want copy support for
my @no_copy;
# node types we don't want equal support for
@@ -125,6 +127,8 @@ my @no_equal;
my @no_query_jumble;
# node types we don't want ddl deparse support for
my @no_ddl_deparse;
+# node types we don't want ddl alter deparse support for
+my @no_ddl_alt_deparse;
# node types we don't want read support for
my @no_read;
# node types we don't want read/write support for
@@ -167,6 +171,7 @@ push @no_copy, qw(List);
push @no_equal, qw(List);
push @no_query_jumble, qw(List);
push @no_ddl_deparse, qw(List);
+push @no_ddl_alt_deparse, qw(List);
push @special_read_write, qw(List);
# Nodes with custom copy/equal implementations are skipped from
@@ -200,6 +205,7 @@ my $next_input_file = 0;
foreach my $infile (@ARGV)
{
my $in_struct;
+ my $in_enum;
my $subline;
my $is_node_struct;
my $supertype;
@@ -248,7 +254,7 @@ foreach my $infile (@ARGV)
next if $line =~ /^#(define|ifdef|endif)/;
# within a struct, don't process until we have whole logical line
- if ($in_struct && $subline > 0)
+ if (($in_struct) && $subline > 0)
{
if ($line =~ /;$/)
{
@@ -269,6 +275,134 @@ foreach my $infile (@ARGV)
}
}
+ # we are analyzing a struct definition
+ if ($in_enum)
+ {
+ $subline++;
+
+ # first line should have opening brace
+ if ($subline == 1)
+ {
+ next if $line eq '{';
+ die "$infile:$lineno: expected opening brace\n";
+ }
+ # second line could be node attributes
+ elsif ($subline == 2
+ && $line =~ /^\s*pg_node_attr\(([\w(), ]*)\)$/)
+ {
+ $node_attrs = $1;
+ $node_attrs_lineno = $lineno;
+ # hack: don't count the line
+ $subline--;
+ next;
+ }
+ # next line should have node tag or supertype
+ elsif ($subline == 2)
+ {
+ if ($line =~ /^\s*NodeTag\s+type;/)
+ {
+ $is_node_struct = 1;
+ next;
+ }
+ elsif ($line =~ /\s*(\w+),/ and elem $1, @node_types)
+ {
+ $is_node_struct = 1;
+ $supertype = $1;
+ $supertype_field = $2;
+ next;
+ }
+ }
+
+ # end of enum
+ if ($line =~ /^\}\s*(?:\Q$in_enum\E\s*)?;$/)
+ {
+ # field names, types, attributes
+ my @f = @my_fields;
+ my %fa = %my_field_attrs;
+
+ # save in global info structure
+ $enum_type_info{$in_enum}->{fields} = \@f;
+ $enum_type_info{$in_enum}->{field_attrs} = \%fa;
+
+ # start new cycle
+ $in_enum = undef;
+ $node_attrs = '';
+ @my_fields = ();
+ %my_field_types = ();
+ %my_field_attrs = ();
+ }
+ # normal enum field
+ elsif ($line =~
+ /^\s*\b(\w+)\s*(?:pg_node_attr\(([\w(\w%{\w}\w:), ]*)\))?,/
+ )
+ {
+ my $name = $1;
+ my $attrs = $2;
+ my $var = $3;
+
+ my @attrs;
+ if ($attrs)
+ {
+ @attrs = split /,\s*/, $attrs;
+ }
+
+ push @my_fields, $name;
+ $my_field_attrs{$name} = \@attrs;
+ }
+ # normal enum field
+ elsif ($line =~
+ /^\s*\b(\w+)\s*(?:pg_node_attr\(([\w(\w:), ]*)\))?/
+ )
+ {
+ my $name = $1;
+ my $attrs = $2;
+ my $var = $3;
+
+ my @attrs;
+ if ($attrs)
+ {
+ @attrs = split /,\s*/, $attrs;
+ foreach my $attr (@attrs)
+ {
+ if ( $attr !~ /^array_size\(\w+\)$/
+ && $attr !~ /^copy_as\(\w+\)$/
+ && $attr !~ /^read_as\(\w+\)$/
+ && $attr !~ /^deparse_as\([\w\s]+\)$/
+ && $attr !~ /^deparse_as\(([\w:]*)\)$/
+ && !elem $attr,
+ qw(copy_as_scalar
+ equal_as_scalar
+ equal_ignore
+ equal_ignore_if_zero
+ query_jumble_ignore
+ query_jumble_location
+ read_write_ignore
+ deparse_ignore
+ write_only_relids
+ write_only_nondefault_pathtarget
+ write_only_req_outer))
+ {
+ die
+ "$infile:$lineno: unrecognized attribute \"$attr\"\n";
+ }
+ }
+ }
+
+ push @my_fields, $name;
+ $my_field_attrs{$name} = \@attrs;
+ }
+ elsif ($line =~ /^\s*/)
+ {
+ next;
+ }
+ else
+ {
+ # We're not too picky about what's outside structs,
+ # but we'd better understand everything inside.
+ die "$infile:$lineno: could not parse enum field\"$line\"\n";
+ }
+ }
+
# we are analyzing a struct definition
if ($in_struct)
{
@@ -576,6 +710,18 @@ foreach my $infile (@ARGV)
elsif ($line =~ /^typedef enum (\w+)(\s*\/\*.*)?$/)
{
push @enum_types, $1;
+
+ if ($1 eq 'AlterTableType')
+ {
+ $in_enum = $1;
+ $subline = 0;
+ }
+ }
+
+ # end of enum
+ if ($in_enum and $line =~ /^\}\s*(?:\Q$in_enum\E\s*)?;$/)
+ {
+ $in_enum = undef;
}
}
}
@@ -1425,8 +1571,6 @@ deparse_${n}(JsonbParseState *state, Oid objectId, Relation relation, Node *pars
{
$read_as_field1 = $2;
$read_as_field2 = $3;
- print "field1 = $2\n";
- print "field2 = $3\n";
}
elsif ($a eq 'deparse_ignore')
{
@@ -1561,6 +1705,97 @@ deparse_${n}(JsonbParseState *state, Oid objectId, Relation relation, Node *pars
close $ddlff;
close $ddlfs;
+
+# ddldeparsefuncs_alter.switch.c
+
+push @output_files, 'ddldeparsefuncs_alter.switch.c';
+open my $ddlalterfs, '>', "$output_path/ddldeparsefuncs_alter.switch.c$tmpext" or die $!;
+
+printf $ddlalterfs $header_comment, 'ddldeparsefuncs_alter.switch.c';
+
+my @enum_ddl_deparse_alter;
+push @enum_ddl_deparse_alter, "AlterTableType";
+
+foreach my $n (@enum_ddl_deparse_alter)
+{
+ # print instructions for each field
+ foreach my $f (@{ $enum_type_info{$n}->{fields} })
+ {
+ my @a = @{ $enum_type_info{$n}->{field_attrs}{$f} };
+ my $ddl_deparse_alter_ignore;
+
+ # extract per-field attributes
+ foreach my $a (@a)
+ {
+ if ($a =~ /^deparse_as\((([\w\s]+):([\w\s]+))\)$/)
+ {
+ print $ddlalterfs "\t\t\tcase ${f}:\n"
+ . "\t\t\t\tpushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);\n"
+ . "\t\t\t\tnew_jsonb_VA(state, $2, \"fmt\", jbvString, \"$3\");\n"
+ . "\t\t\t\tpushJsonbValue(&state, WJB_END_OBJECT, NULL);\n"
+ . "\t\t\t\tbreak;\n"
+ unless $ddl_deparse_alter_ignore;
+ }
+ elsif ($a =~ /^deparse_as\((([\w\s]+):([\w\s]+):([\w\s]+):([\w\s]+))\)$/)
+ {
+ print $ddlalterfs "\t\t\tcase ${f}:\n"
+ . "\t\t\t\tpushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);\n"
+ . "\t\t\t\tnew_jsonb_VA(state, $2,\n"
+ . "\t\t\t\t \"fmt\", jbvString, \"$3\",\n"
+ . "\t\t\t\t \"$4\", jbvString, \"$5\");\n"
+ . "\t\t\t\tpushJsonbValue(&state, WJB_END_OBJECT, NULL);\n"
+ . "\t\t\t\tbreak;\n"
+ unless $ddl_deparse_alter_ignore;
+ }
+ elsif ($a =~ /^deparse_as\((([\w\s]+):([\w\s%{\w}\w\s]+):([\w\s]+):([\w\s]+):([\w\s]+):([\w\s]+))\)$/)
+ {
+ print $ddlalterfs "\t\t\tcase ${f}:\n"
+ . "\t\t\t\tpushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);\n"
+ . "\t\t\t\tnew_jsonb_VA(state, $2,\n"
+ . "\t\t\t\t \"fmt\", jbvString,\n"
+ . "\t\t\t\t \"$3\",\n"
+ . "\t\t\t\t \"$4\", jbvString, \"$5\",\n"
+ . "\t\t\t\t \"$6\", jbvString, $7);\n"
+ . "\t\t\t\tpushJsonbValue(&state, WJB_END_OBJECT, NULL);\n"
+ . "\t\t\t\tbreak;\n"
+ unless $ddl_deparse_alter_ignore;
+ }
+ elsif ($a =~ /^deparse_as\((([\w\s]+):([\w\s%{\w}\w\s]+):([\w\s]+):([\w\s]+):([\w\s]+):([\w\s]+):([\w\s]+):([\w\s]+))\)$/)
+ {
+ print $ddlalterfs "\t\t\tcase ${f}:\n"
+ . "\t\t\t\tpushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);\n"
+ . "\t\t\t\tnew_jsonb_VA(state, $2,\n"
+ . "\t\t\t\t \"fmt\", jbvString,\n"
+ . "\t\t\t\t \"$3\",\n"
+ . "\t\t\t\t \"$4\", jbvString, \"$5\",\n"
+ . "\t\t\t\t \"$6\", jbvString, \"$7\",\n"
+ . "\t\t\t\t \"$8\", jbvString, $9);\n"
+ . "\t\t\t\tpushJsonbValue(&state, WJB_END_OBJECT, NULL);\n"
+ . "\t\t\t\tbreak;\n"
+ unless $ddl_deparse_alter_ignore;
+ }
+ elsif ($a eq 'deparse_ignore')
+ {
+ $ddl_deparse_alter_ignore = 1;
+ }
+ else
+ {
+ die "$a did not match";
+ }
+ }
+
+ if (!@a)
+ {
+ print $ddlalterfs "\t\t\t case ${f}:\n"
+ . "\t\t\t\t /* Subtypes used for internal operations; nothing to do here */\n"
+ . "\t\t\t\t break;\n"
+ unless $ddl_deparse_alter_ignore;
+ }
+ }
+}
+
+close $ddlalterfs;
+
# now rename the temporary files to their final names
foreach my $file (@output_files)
{
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 86532a3f02..c5ff3189c5 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2170,73 +2170,150 @@ typedef struct AlterTableStmt
bool table_like; /* internally generated for TableLikeClause */
} AlterTableStmt;
+/*
+ * Various annotations are used for auto generating the required jsonb code for
+ * the sub commands:
+ * a) deparse_as: It uses the following format
+ * deparse_as(count:format:key-2:val-2:key-3:val-3:...:key-n:val-n)
+ * In the above 1) count means the number of key value pairs 2) Specify the
+ * format for this command (No need to specify key for format as we always use
+ * "fmt" as key for format). 3) key-n:val-n are the key/values pairs that are
+ * required to generate the command.
+ * b) deparse_ignore: This field will have custom implementation. This will be
+ * used for complex implementation where it will require accessing catalog
+ * tables, it will skip generation of code in this case.
+ * c) no annotation: This can be used in cases which don't require any
+ * implementation, it will just add a case and break statement without any
+ * implementation.
+ */
typedef enum AlterTableType
{
- AT_AddColumn, /* add column */
- AT_AddColumnToView, /* implicitly via CREATE OR REPLACE VIEW */
- AT_ColumnDefault, /* alter column default */
- AT_CookedColumnDefault, /* add a pre-cooked column default */
- AT_DropNotNull, /* alter column drop not null */
- AT_SetNotNull, /* alter column set not null */
- AT_DropExpression, /* alter column drop expression */
- AT_CheckNotNull, /* check column is already marked not null */
- AT_SetStatistics, /* alter column set statistics */
- AT_SetOptions, /* alter column set ( options ) */
- AT_ResetOptions, /* alter column reset ( options ) */
- AT_SetStorage, /* alter column set storage */
- AT_SetCompression, /* alter column set compression */
- AT_DropColumn, /* drop column */
- AT_AddIndex, /* add index */
- AT_ReAddIndex, /* internal to commands/tablecmds.c */
- AT_AddConstraint, /* add constraint */
+ /* add column */
+ AT_AddColumn pg_node_attr(deparse_ignore),
+ /* implicitly via CREATE OR REPLACE VIEW */
+ AT_AddColumnToView pg_node_attr(deparse_ignore),
+ /* alter column default */
+ AT_ColumnDefault pg_node_attr(deparse_ignore),
+ /* add a pre-cooked column default */
+ AT_CookedColumnDefault pg_node_attr(deparse_ignore),
+ /* alter column drop not null */
+ AT_DropNotNull pg_node_attr(deparse_as(3:ALTER COLUMN %{column}I DROP NOT NULL:type:drop not null:column:name)),
+ /* alter column set not null */
+ AT_SetNotNull pg_node_attr(deparse_as(3:ALTER COLUMN %{column}I SET NOT NULL:type:set not null:column:name)),
+ /* alter column drop expression */
+ AT_DropExpression pg_node_attr(deparse_ignore),
+ /* check column is already marked not null */
+ AT_CheckNotNull,
+ /* alter column set statistics */
+ AT_SetStatistics pg_node_attr(deparse_ignore),
+ /* alter column set ( options ) */
+ AT_SetOptions pg_node_attr(deparse_ignore),
+ /* alter column reset ( options ) */
+ AT_ResetOptions pg_node_attr(deparse_ignore),
+ /* alter column set storage */
+ AT_SetStorage pg_node_attr(deparse_ignore),
+ /* alter column set compression */
+ AT_SetCompression pg_node_attr(deparse_ignore),
+ /* drop column */
+ AT_DropColumn pg_node_attr(deparse_ignore),
+ /* add index */
+ AT_AddIndex pg_node_attr(deparse_ignore),
+ /* internal to commands/tablecmds.c */
+ AT_ReAddIndex,
+ /* add constraint */
+ AT_AddConstraint pg_node_attr(deparse_ignore),
AT_ReAddConstraint, /* internal to commands/tablecmds.c */
AT_ReAddDomainConstraint, /* internal to commands/tablecmds.c */
- AT_AlterConstraint, /* alter constraint */
- AT_ValidateConstraint, /* validate constraint */
- AT_AddIndexConstraint, /* add constraint using existing index */
- AT_DropConstraint, /* drop constraint */
+ /* alter constraint */
+ AT_AlterConstraint pg_node_attr(deparse_ignore),
+ /* validate constraint */
+ AT_ValidateConstraint pg_node_attr(deparse_as(3:VALIDATE CONSTRAINT %{constraint}I:type:validate constraint:constraint:name)),
+ /* add constraint using existing index */
+ AT_AddIndexConstraint pg_node_attr(deparse_ignore),
+ /* drop constraint */
+ AT_DropConstraint pg_node_attr(deparse_ignore),
AT_ReAddComment, /* internal to commands/tablecmds.c */
- AT_AlterColumnType, /* alter column type */
- AT_AlterColumnGenericOptions, /* alter column OPTIONS (...) */
- AT_ChangeOwner, /* change owner */
- AT_ClusterOn, /* CLUSTER ON */
- AT_DropCluster, /* SET WITHOUT CLUSTER */
- AT_SetLogged, /* SET LOGGED */
- AT_SetUnLogged, /* SET UNLOGGED */
- AT_DropOids, /* SET WITHOUT OIDS */
- AT_SetAccessMethod, /* SET ACCESS METHOD */
- AT_SetTableSpace, /* SET TABLESPACE */
- AT_SetRelOptions, /* SET (...) -- AM specific parameters */
- AT_ResetRelOptions, /* RESET (...) -- AM specific parameters */
+ /* alter column type */
+ AT_AlterColumnType pg_node_attr(deparse_ignore),
+ /* alter column OPTIONS (...) */
+ AT_AlterColumnGenericOptions pg_node_attr(deparse_ignore),
+ /* change owner */
+ AT_ChangeOwner pg_node_attr(deparse_as(3:OWNER TO %{owner}I:type:change owner:owner:GET_ROLE_SPEC_DDL_ALTER_TBL)),
+ /* CLUSTER ON */
+ AT_ClusterOn pg_node_attr(deparse_as(3:CLUSTER ON %{index}I:type:cluster on:index:name)),
+ /* SET WITHOUT CLUSTER */
+ AT_DropCluster pg_node_attr(deparse_as(2:SET WITHOUT CLUSTER:type:set without cluster)),
+ /* SET LOGGED */
+ AT_SetLogged pg_node_attr(deparse_as(2:SET LOGGED:type:set logged)),
+ /* SET UNLOGGED */
+ AT_SetUnLogged pg_node_attr(deparse_as(2:SET UNLOGGED:type:set unlogged)),
+ /* SET WITHOUT OIDS */
+ AT_DropOids pg_node_attr(deparse_as(2:SET WITHOUT OIDS:type:set without oids)),
+ /* SET ACCESS METHOD */
+ AT_SetAccessMethod pg_node_attr(deparse_as(3:SET ACCESS METHOD %{access_method}I:type:set access method:access_method:name)),
+ /* SET TABLESPACE */
+ AT_SetTableSpace pg_node_attr(deparse_as(3:SET TABLESPACE %{tablespace}I:type:set tablespace:tablespace:name)),
+ /* SET (...) -- AM specific parameters */
+ AT_SetRelOptions pg_node_attr(deparse_ignore),
+ /* RESET (...) -- AM specific parameters */
+ AT_ResetRelOptions pg_node_attr(deparse_ignore),
AT_ReplaceRelOptions, /* replace reloption list in its entirety */
- AT_EnableTrig, /* ENABLE TRIGGER name */
- AT_EnableAlwaysTrig, /* ENABLE ALWAYS TRIGGER name */
- AT_EnableReplicaTrig, /* ENABLE REPLICA TRIGGER name */
- AT_DisableTrig, /* DISABLE TRIGGER name */
- AT_EnableTrigAll, /* ENABLE TRIGGER ALL */
- AT_DisableTrigAll, /* DISABLE TRIGGER ALL */
- AT_EnableTrigUser, /* ENABLE TRIGGER USER */
- AT_DisableTrigUser, /* DISABLE TRIGGER USER */
- AT_EnableRule, /* ENABLE RULE name */
- AT_EnableAlwaysRule, /* ENABLE ALWAYS RULE name */
- AT_EnableReplicaRule, /* ENABLE REPLICA RULE name */
- AT_DisableRule, /* DISABLE RULE name */
- AT_AddInherit, /* INHERIT parent */
- AT_DropInherit, /* NO INHERIT parent */
- AT_AddOf, /* OF <type_name> */
- AT_DropOf, /* NOT OF */
- AT_ReplicaIdentity, /* REPLICA IDENTITY */
- AT_EnableRowSecurity, /* ENABLE ROW SECURITY */
- AT_DisableRowSecurity, /* DISABLE ROW SECURITY */
- AT_ForceRowSecurity, /* FORCE ROW SECURITY */
- AT_NoForceRowSecurity, /* NO FORCE ROW SECURITY */
- AT_GenericOptions, /* OPTIONS (...) */
- AT_AttachPartition, /* ATTACH PARTITION */
- AT_DetachPartition, /* DETACH PARTITION */
- AT_DetachPartitionFinalize, /* DETACH PARTITION FINALIZE */
- AT_AddIdentity, /* ADD IDENTITY */
- AT_SetIdentity, /* SET identity column options */
- AT_DropIdentity, /* DROP IDENTITY */
+ /* ENABLE TRIGGER name */
+ AT_EnableTrig pg_node_attr(deparse_as(3:ENABLE TRIGGER %{trigger}I:type:enable trigger:trigger:name)),
+ /* ENABLE ALWAYS TRIGGER name */
+ AT_EnableAlwaysTrig pg_node_attr(deparse_as(3:ENABLE ALWAYS TRIGGER %{trigger}I:type:enable always trigger:trigger:name)),
+ /* ENABLE REPLICA TRIGGER name */
+ AT_EnableReplicaTrig pg_node_attr(deparse_as(3:ENABLE REPLICA TRIGGER %{trigger}I:type:enable replica trigger:trigger:name)),
+ /* DISABLE TRIGGER name */
+ AT_DisableTrig pg_node_attr(deparse_as(3:DISABLE TRIGGER %{trigger}I:type:disable trigger:trigger:name)),
+ /* ENABLE TRIGGER ALL */
+ AT_EnableTrigAll pg_node_attr(deparse_as(2:ENABLE TRIGGER ALL:type:enable trigger all)),
+ /* DISABLE TRIGGER ALL */
+ AT_DisableTrigAll pg_node_attr(deparse_as(2:DISABLE TRIGGER ALL:type:disable trigger all)),
+ /* ENABLE TRIGGER USER */
+ AT_EnableTrigUser pg_node_attr(deparse_as(2:ENABLE TRIGGER USER:type:enable trigger user)),
+ /* DISABLE TRIGGER USER */
+ AT_DisableTrigUser pg_node_attr(deparse_as(2:DISABLE TRIGGER USER:type:disable trigger user)),
+ /* ENABLE RULE name */
+ AT_EnableRule pg_node_attr(deparse_as(3:ENABLE RULE %{rule}I:type:enable rule:rule:name)),
+ /* ENABLE ALWAYS RULE name */
+ AT_EnableAlwaysRule pg_node_attr(deparse_as(3:ENABLE ALWAYS RULE %{rule}I:type:enable always rule:rule:name)),
+ /* ENABLE REPLICA RULE name */
+ AT_EnableReplicaRule pg_node_attr(deparse_as(3:ENABLE REPLICA RULE %{rule}I:type:enable replica rule:rule:name)),
+ /* DISABLE RULE name */
+ AT_DisableRule pg_node_attr(deparse_as(3:DISABLE RULE %{rule}I:type:disable rule:rule:name)),
+ /* INHERIT parent */
+ AT_AddInherit pg_node_attr(deparse_ignore),
+ /* NO INHERIT parent */
+ AT_DropInherit pg_node_attr(deparse_ignore),
+ /* OF <type_name> */
+ AT_AddOf pg_node_attr(deparse_ignore),
+ /* NOT OF */
+ AT_DropOf pg_node_attr(deparse_as(2:NOT OF:type:not of)),
+ /* REPLICA IDENTITY */
+ AT_ReplicaIdentity pg_node_attr(deparse_ignore),
+ /* ENABLE ROW SECURITY */
+ AT_EnableRowSecurity pg_node_attr(deparse_as(2:ENABLE ROW LEVEL SECURITY:type:enable row security)),
+ /* DISABLE ROW SECURITY */
+ AT_DisableRowSecurity pg_node_attr(deparse_as(2:DISABLE ROW LEVEL SECURITY:type:disable row security)),
+ /* FORCE ROW SECURITY */
+ AT_ForceRowSecurity pg_node_attr(deparse_as(1:FORCE ROW LEVEL SECURITY)),
+ /* NO FORCE ROW SECURITY */
+ AT_NoForceRowSecurity pg_node_attr(deparse_as(1:NO FORCE ROW LEVEL SECURITY)),
+ /* OPTIONS (...) */
+ AT_GenericOptions pg_node_attr(deparse_ignore),
+ /* ATTACH PARTITION */
+ AT_AttachPartition pg_node_attr(deparse_ignore),
+ /* DETACH PARTITION */
+ AT_DetachPartition pg_node_attr(deparse_ignore),
+ /* DETACH PARTITION FINALIZE */
+ AT_DetachPartitionFinalize pg_node_attr(deparse_ignore),
+ /* ADD IDENTITY */
+ AT_AddIdentity pg_node_attr(deparse_ignore),
+ /* SET identity column options */
+ AT_SetIdentity pg_node_attr(deparse_ignore),
+ /* DROP IDENTITY */
+ AT_DropIdentity pg_node_attr(deparse_ignore),
AT_ReAddStatistics /* internal to commands/tablecmds.c */
} AlterTableType;
--
2.34.1