diff --git a/lib/SQL/Translator/Parser/PostgreSQL.pm b/lib/SQL/Translator/Parser/PostgreSQL.pm index 37f657996..f6ef08b0a 100644 --- a/lib/SQL/Translator/Parser/PostgreSQL.pm +++ b/lib/SQL/Translator/Parser/PostgreSQL.pm @@ -366,6 +366,7 @@ column_name : NAME '.' NAME comment_phrase : /null/i { $return = 'NULL' } | SQSTRING + | DOLLARSTRING field : field_comment(s?) field_name data_type field_meta(s?) field_comment(s?) { diff --git a/lib/SQL/Translator/Producer/PostgreSQL.pm b/lib/SQL/Translator/Producer/PostgreSQL.pm index 7520563ff..f77167dec 100644 --- a/lib/SQL/Translator/Producer/PostgreSQL.pm +++ b/lib/SQL/Translator/Producer/PostgreSQL.pm @@ -17,6 +17,40 @@ producer. Now handles PostGIS Geometry and Geography data types on table definitions. Does not yet support PostGIS Views. +=head2 Producer Args + +=over 4 + +=item postgres_version + +The version of postgres to generate DDL for. Turns on features only available in later versions. The following features are supported + +=over 4 + +=item IF EXISTS + +If your postgres_version is higher than 8.003 (I should hope it is by now), then the DDL +generated for dropping objects in the database will contain IF EXISTS. + +=back + +=item attach_comments + +Generates table and column comments via the COMMENT command rather than as a comment in +the DDL. You could then look it up with \dt+ or \d+ (for tables and columns respectively) +in psql. The comment is dollar quoted with $comment$ so you can include ' in it. Just to clarify: you get this + + CREATE TABLE foo ...; + COMMENT on TABLE foo IS $comment$hi there$comment$; + +instead of this + + -- comment + CREAT TABLE foo ...; + +=back + + =cut use strict; @@ -163,6 +197,7 @@ sub produce { postgres_version => $postgres_version, add_drop_table => $add_drop_table, type_defs => \%type_defs, + attach_comments => $pargs->{attach_comments} }); push @table_defs, $table_def; @@ -265,6 +300,7 @@ sub create_table my $add_drop_table = $options->{add_drop_table} || 0; my $postgres_version = $options->{postgres_version} || 0; my $type_defs = $options->{type_defs} || {}; + my $attach_comments = $options->{attach_comments}; my $table_name = $table->name or next; my $table_name_qt = $generator->quote($table_name); @@ -273,9 +309,18 @@ sub create_table push @comments, "--\n-- Table: $table_name\n--\n" unless $no_comments; - if ( !$no_comments and my $comments = $table->comments ) { - $comments =~ s/^/-- /mg; - push @comments, "-- Comments:\n$comments\n--\n"; + my @comment_statements; + if ( my $comments = $table->comments ) { + if ( $attach_comments) { + # this follows the example in the MySQL producer, where all comments are added as + # table comments, even though they could have originally been parsed as DDL comments + # quoted via $$ string so there can be 'quotes' inside the comments + my $comment_ddl = "COMMENT on TABLE $table_name_qt IS \$comment\$$comments\$comment\$"; + push @comment_statements, $comment_ddl; + } elsif (!$no_comments) { + $comments =~ s/^/-- /mg; + push @comments, "-- Comments:\n$comments\n--\n"; + } } # @@ -287,7 +332,17 @@ sub create_table postgres_version => $postgres_version, type_defs => $type_defs, constraint_defs => \@constraint_defs, + attach_comments => $attach_comments }); + if ( $attach_comments ) { + my $field_comments = $field->comments; + next unless $field_comments; + my $field_name_qt = $generator->quote($field->name); + my $comment_ddl = + "COMMENT on COLUMN $table_name_qt.$field_name_qt IS \$comment\$$field_comments\$comment\$"; + push @comment_statements, $comment_ddl; + } + } # @@ -338,6 +393,10 @@ sub create_table $create_statement .= join(";\n", '', map{ add_geometry_column($_, $options) } @geometry_columns); } + if (@comment_statements) { + $create_statement .= join(";\n", '', @comment_statements); + } + return $create_statement, \@fks; } @@ -395,11 +454,13 @@ sub create_view { my $constraint_defs = $options->{constraint_defs} || []; my $postgres_version = $options->{postgres_version} || 0; my $type_defs = $options->{type_defs} || {}; + my $attach_comments = $options->{attach_comments}; $field_name_scope{$table_name} ||= {}; my $field_name = $field->name; + my $field_comments = ''; - if (my $comments = $field->comments) { + if ( !$attach_comments and my $comments = $field->comments ) { $comments =~ s/(?new( no_comments => 1, show_warnings => 0, add_drop_table => 1, + producer_args => { attach_comments => 1 } ); die "Can't find test schema $xmlfile" unless -e $xmlfile; @@ -42,7 +43,6 @@ CREATE TABLE "Basic" ( "email" character varying(500), "explicitnulldef" character varying, "explicitemptystring" character varying DEFAULT '', - -- Hello emptytagdef "emptytagdef" character varying DEFAULT '', "another_id" integer DEFAULT 2, "timest" timestamp, @@ -51,6 +51,7 @@ CREATE TABLE "Basic" ( CONSTRAINT "very_long_index_name_on_title_field_which_should_be_truncated_for_various_rdbms" UNIQUE ("title") ); CREATE INDEX "titleindex" on "Basic" ("title"); +COMMENT on COLUMN "Basic"."emptytagdef" IS \$comment\$Hello emptytagdef\$comment\$; DROP TABLE "Another" CASCADE; CREATE TABLE "Another" ( diff --git a/t/47postgres-producer.t b/t/47postgres-producer.t index 9c50db736..ee952fd3e 100644 --- a/t/47postgres-producer.t +++ b/t/47postgres-producer.t @@ -38,25 +38,23 @@ my $PRODUCER = \&SQL::Translator::Producer::PostgreSQL::create_field; is_foreign_key => 0, is_unique => 0 ); $table->add_field($field); - my ($create, $fks) = SQL::Translator::Producer::PostgreSQL::create_table($table, { quote_table_names => q{"} }); + my ($create, $fks) = SQL::Translator::Producer::PostgreSQL::create_table( + $table, { quote_table_names => q{"}, attach_comments => 1 }); is($table->name, 'foo.bar'); my $expected = < {}, parser_args => {}, }, + { + engine => 'PostgreSQL', + name => 'Postgres w/ attached comments', + producer_args => { attach_comments => 1 }, + parser_args => {}, + }, { engine => 'SQLServer', producer_args => {},