From: Aaron Schrab Date: Tue, 27 Dec 2011 23:27:14 +0000 (-0500) Subject: Applied patch from RT#49627 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Ftopic%2Fpg_inheritance;p=dbsrgits%2FSQL-Translator.git Applied patch from RT#49627 --- diff --git a/Changes b/Changes index a9d37ea..afc4cd6 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ closes RT#70734, RT#71283, RT#70378 * Proper quoting support in SQLite * Support for triggers in PostgreSQL producer and parser +* Support for INHERITS statements in PG parser/producer + (RT#49627, patch from Vincent Veselosky) * Correct Data Type in SQLT::Parser::DBI::PostgreSQL (patch from Andrew Pam) * Fix index issue in SQLT::Parser::DBI::PostgreSQL * Add column and table comments in SQLT::Parser::DBI::PostgreSQL(patch from Andrew Pam) diff --git a/lib/SQL/Translator/Parser/PostgreSQL.pm b/lib/SQL/Translator/Parser/PostgreSQL.pm index 29f26ab..d301d3a 100644 --- a/lib/SQL/Translator/Parser/PostgreSQL.pm +++ b/lib/SQL/Translator/Parser/PostgreSQL.pm @@ -1051,6 +1051,8 @@ sub parse { ) or die "Couldn't create table '$table_name': " . $schema->error; $table->extra(temporary => 1) if $tdata->{'temporary'}; + $table->extra(inherits => $tdata->{'table_options(s?)'}{inherits}{table_name}) + if $tdata->{'table_options(s?)'}{inherits}; $table->comments( $tdata->{'comments'} ); diff --git a/lib/SQL/Translator/Producer/PostgreSQL.pm b/lib/SQL/Translator/Producer/PostgreSQL.pm index c994817..42875f1 100644 --- a/lib/SQL/Translator/Producer/PostgreSQL.pm +++ b/lib/SQL/Translator/Producer/PostgreSQL.pm @@ -267,8 +267,8 @@ sub mk_name { sub is_geometry { - my $field = shift; - return 1 if $field->data_type eq 'geometry'; + my $field = shift; + return 1 if $field->data_type eq 'geometry'; } sub is_geography @@ -357,6 +357,10 @@ sub create_table if(exists $table->{extra}{temporary}) { $temporary = $table->{extra}{temporary} ? "TEMPORARY " : ""; } + my $inherits = ""; + if(my $tlist = $table->extra('inherits')) { + $inherits = sprintf(' INHERITS (%s)', join(', ',@$tlist)); + } my $create_statement; $create_statement = join("\n", @comments); @@ -369,22 +373,22 @@ sub create_table } $create_statement .= qq[CREATE ${temporary}TABLE $qt$table_name_ur$qt (\n]. join( ",\n", map { " $_" } @field_defs, @constraint_defs ). - "\n)" + "\n)$inherits" ; $create_statement .= @index_defs ? ';' : q{}; $create_statement .= ( $create_statement =~ /;$/ ? "\n" : q{} ) . join(";\n", @index_defs); - # - # Geometry - # - if(grep { is_geometry($_) } $table->get_fields){ + # + # Geometry + # + if(grep { is_geometry($_) } $table->get_fields){ $create_statement .= ";"; my @geometry_columns; foreach my $col ($table->get_fields) { push(@geometry_columns,$col) if is_geometry($col); } - $create_statement .= "\n".join("\n", map{ drop_geometry_column($_) } @geometry_columns) if $options->{add_drop_table}; - $create_statement .= "\n".join("\n", map{ add_geometry_column($_) } @geometry_columns); - } + $create_statement .= "\n".join("\n", map{ drop_geometry_column($_) } @geometry_columns) if $options->{add_drop_table}; + $create_statement .= "\n".join("\n", map{ add_geometry_column($_) } @geometry_columns); + } return $create_statement, \@fks; } @@ -496,20 +500,20 @@ sub create_view { # $field_def .= ' NOT NULL' unless $field->is_nullable; - # - # Geometry constraints - # - if(is_geometry($field)){ - foreach ( create_geometry_constraints($field) ) { - my ($cdefs, $fks) = create_constraint($_, - { - quote_field_names => $qf, - quote_table_names => $qt, - table_name => $table_name, - }); - push @$constraint_defs, @$cdefs; - push @$fks, @$fks; - } + # + # Geometry constraints + # + if(is_geometry($field)){ + foreach ( create_geometry_constraints($field) ) { + my ($cdefs, $fks) = create_constraint($_, + { + quote_field_names => $qf, + quote_table_names => $qt, + table_name => $table_name, + }); + push @$constraint_defs, @$cdefs; + push @$fks, @$fks; + } } return $field_def; @@ -517,30 +521,30 @@ sub create_view { } sub create_geometry_constraints{ - my $field = shift; - - my @constraints; - push @constraints, SQL::Translator::Schema::Constraint->new( - name => "enforce_dims_".$field->name, - expression => "(ST_NDims($field) = ".$field->{extra}{dimensions}.")", - table => $field->table, - type => CHECK_C, - ); - - push @constraints, SQL::Translator::Schema::Constraint->new( - name => "enforce_srid_".$field->name, - expression => "(ST_SRID($field) = ".$field->{extra}{srid}.")", - table => $field->table, - type => CHECK_C, - ); - push @constraints, SQL::Translator::Schema::Constraint->new( - name => "enforce_geotype_".$field->name, - expression => "(GeometryType($field) = '".$field->{extra}{geometry_type}."'::text OR $field IS NULL)", - table => $field->table, - type => CHECK_C, - ); - - return @constraints; + my $field = shift; + + my @constraints; + push @constraints, SQL::Translator::Schema::Constraint->new( + name => "enforce_dims_".$field->name, + expression => "(ST_NDims($field) = ".$field->{extra}{dimensions}.")", + table => $field->table, + type => CHECK_C, + ); + + push @constraints, SQL::Translator::Schema::Constraint->new( + name => "enforce_srid_".$field->name, + expression => "(ST_SRID($field) = ".$field->{extra}{srid}.")", + table => $field->table, + type => CHECK_C, + ); + push @constraints, SQL::Translator::Schema::Constraint->new( + name => "enforce_geotype_".$field->name, + expression => "(GeometryType($field) = '".$field->{extra}{geometry_type}."'::text OR $field IS NULL)", + table => $field->table, + type => CHECK_C, + ); + + return @constraints; } sub create_index @@ -815,10 +819,10 @@ sub alter_field if ( defined $new_default && (!defined $old_default || $old_default ne $new_default) ); - # fixes bug where removing the DEFAULT statement of a column - # would result in no change + # fixes bug where removing the DEFAULT statement of a column + # would result in no change - push @out, sprintf('ALTER TABLE %s ALTER COLUMN %s DROP DEFAULT', + push @out, sprintf('ALTER TABLE %s ALTER COLUMN %s DROP DEFAULT', $to_field->table->name, $to_field->name) if ( !defined $new_default && defined $old_default ); @@ -855,53 +859,53 @@ sub drop_field my $out = sprintf('ALTER TABLE %s DROP COLUMN %s', $qt . $old_field->table->name . $qt, $qf . $old_field->name . $qf); - $out .= "\n".drop_geometry_column($old_field) if is_geometry($old_field); + $out .= "\n".drop_geometry_column($old_field) if is_geometry($old_field); return $out; } sub add_geometry_column{ - my ($field,$options) = @_; - - my $out = sprintf("INSERT INTO geometry_columns VALUES ('%s','%s','%s','%s','%s','%s','%s')", - '', - $field->table->schema->name, - $options->{table} ? $options->{table} : $field->table->name, - $field->name, - $field->{extra}{dimensions}, - $field->{extra}{srid}, - $field->{extra}{geometry_type}); + my ($field,$options) = @_; + + my $out = sprintf("INSERT INTO geometry_columns VALUES ('%s','%s','%s','%s','%s','%s','%s')", + '', + $field->table->schema->name, + $options->{table} ? $options->{table} : $field->table->name, + $field->name, + $field->{extra}{dimensions}, + $field->{extra}{srid}, + $field->{extra}{geometry_type}); return $out; } sub drop_geometry_column { - my $field = shift; + my $field = shift; - my $out = sprintf("DELETE FROM geometry_columns WHERE f_table_schema = '%s' AND f_table_name = '%s' AND f_geometry_column = '%s'", - $field->table->schema->name, - $field->table->name, - $field->name); + my $out = sprintf("DELETE FROM geometry_columns WHERE f_table_schema = '%s' AND f_table_name = '%s' AND f_geometry_column = '%s'", + $field->table->schema->name, + $field->table->name, + $field->name); return $out; } sub add_geometry_constraints{ - my $field = shift; + my $field = shift; - my @constraints = create_geometry_constraints($field); + my @constraints = create_geometry_constraints($field); - my $out = join("\n", map { alter_create_constraint($_); } @constraints); + my $out = join("\n", map { alter_create_constraint($_); } @constraints); - return $out; + return $out; } sub drop_geometry_constraints{ - my $field = shift; + my $field = shift; - my @constraints = create_geometry_constraints($field); + my @constraints = create_geometry_constraints($field); - my $out = join("\n", map { alter_drop_constraint($_); } @constraints); + my $out = join("\n", map { alter_drop_constraint($_); } @constraints); - return $out; + return $out; } sub alter_table { @@ -919,9 +923,9 @@ sub rename_table { my $qt = $options->{quote_table_names} || ''; $options->{alter_table_action} = "RENAME TO $qt$new_table$qt"; - my @geometry_changes; - push @geometry_changes, map { drop_geometry_column($_); } grep { is_geometry($_) } $old_table->get_fields; - push @geometry_changes, map { add_geometry_column($_, { table => $new_table }); } grep { is_geometry($_) } $old_table->get_fields; + my @geometry_changes; + push @geometry_changes, map { drop_geometry_column($_); } grep { is_geometry($_) } $old_table->get_fields; + push @geometry_changes, map { add_geometry_column($_, { table => $new_table }); } grep { is_geometry($_) } $old_table->get_fields; $options->{geometry_changes} = join ("\n",@geometry_changes) if scalar(@geometry_changes); @@ -957,7 +961,7 @@ sub alter_drop_constraint { return sprintf( 'ALTER TABLE %s DROP CONSTRAINT %s', - $qt . $c->table->name . $qt, + $qt . $c->table->name . $qt, # attention: Postgres has a very special naming structure # for naming foreign keys, it names them uses the name of # the table as prefix and fkey as suffix, concatenated by a underscore diff --git a/t/14postgres-parser.t b/t/14postgres-parser.t index fd60cb0..cbe8e3b 100644 --- a/t/14postgres-parser.t +++ b/t/14postgres-parser.t @@ -8,7 +8,7 @@ use SQL::Translator::Schema::Constants; use Test::SQL::Translator qw(maybe_plan); BEGIN { - maybe_plan(134, 'SQL::Translator::Parser::PostgreSQL'); + maybe_plan(147, 'SQL::Translator::Parser::PostgreSQL'); SQL::Translator::Parser::PostgreSQL->import('parse'); } @@ -40,6 +40,12 @@ my $sql = q{ check (f_int between 1 and 5) ); + create table t_test3 ( + test_field varchar(25) + ) inherits (t_test2); + + create table t_test4 () inherits (t_test3); + CREATE TABLE products_1 ( product_no integer, name text, @@ -108,7 +114,7 @@ my $schema = $t->schema; isa_ok( $schema, 'SQL::Translator::Schema', 'Schema object' ); my @tables = $schema->get_tables; -is( scalar @tables, 5, 'Five tables' ); +is( scalar @tables, 7, 'Seven tables' ); my $t1 = shift @tables; is( $t1->name, 't_test1', 'Table t_test1 exists' ); @@ -296,6 +302,30 @@ is( $t2_c2->type, PRIMARY_KEY, "Constraint is a PK" ); my $t2_c3 = shift @t2_constraints; is( $t2_c3->type, CHECK_C, "Constraint is a 'CHECK'" ); +# test table inheritance +my $t3 = shift @tables; +is( $t3->name, 't_test3', 'Table t_test3 exists' ); +is_deeply( $t3->extra->{inherits}, ['t_test2'], 'Table t_test3 inherits from t_test2' ); + +my @t3_fields = $t3->get_fields; +is( scalar @t3_fields, 1, '1 field in t_test3' ); + +my $t3_f1 = shift @t3_fields; +is( $t3_f1->name, 'test_field', 'First field is "test_field"' ); +is( $t3_f1->data_type, 'varchar', 'Field is an varchar' ); +is( $t3_f1->is_nullable, 1, 'Field can be null' ); +is( $t3_f1->size, 25, 'Size is "25"' ); +is( $t3_f1->default_value, undef, 'Default value is undefined' ); +is( $t3_f1->is_primary_key, 0, 'Field is not PK' ); + +my @t3_constraints = $t3->get_constraints; +is( scalar @t3_constraints, 0, "No constraints on table" ); + +my $t4 = shift @tables; +is( $t4->name, 't_test4', 'Table t_test4 exists' ); +is( scalar $t4->get_fields, undef, 'No fields in t_test4' ); +is_deeply( $t4->extra->{inherits}, ['t_test3'], 'Table t_test4 inherits from t_test3' ); + # test temporary tables is( exists $schema->get_table('products_1')->extra()->{'temporary'}, "", "Table is NOT temporary"); is( $schema->get_table('products_2')->extra('temporary'), 1,"Table is TEMP");