Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes Bug #63814: Allow for index creation with USING and WHERE keywords... #51

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions lib/SQL/Translator/Parser/PostgreSQL.pm
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,8 @@ create : CREATE unique(?) /(index|key)/i index_name /on/i table_id using_method(
supertype => $item{'unique'}[0] ? 'constraint' : 'index',
type => $item{'unique'}[0] ? 'unique' : 'normal',
fields => $item[9],
method => $item{'using_method'}[0],
method => $item{'using_method(?)'}[0],
where => $item{'where_predicate(?)'}[0],
}
;
}
Expand Down Expand Up @@ -1075,10 +1076,14 @@ sub parse {
}

for my $idata ( @{ $tdata->{'indices'} || [] } ) {
my @options = ();
push @options, { using => $idata->{'method'} } if $idata->{method};
push @options, { where => $idata->{'where'} } if $idata->{where};
my $index = $table->add_index(
name => $idata->{'name'},
type => uc $idata->{'type'},
fields => $idata->{'fields'},
name => $idata->{'name'},
type => uc $idata->{'type'},
fields => $idata->{'fields'},
options => \@options
) or die $table->error . ' ' . $table->name;
}

Expand Down
21 changes: 19 additions & 2 deletions lib/SQL/Translator/Producer/PostgreSQL.pm
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,23 @@ sub create_index
my @fields = $index->fields;
return unless @fields;

my $index_using;
my $index_where;
for my $opt ( $index->options ) {
if ( ref $opt eq 'HASH' ) {
foreach my $key (keys %$opt) {
my $value = $opt->{$key};
next unless defined $value;
if ( uc($key) eq 'USING' ) {
$index_using = "USING $value";
}
elsif ( uc($key) eq 'WHERE' ) {
$index_where = "WHERE $value";
}
}
}
}

my $def_start = 'CONSTRAINT ' . $generator->quote($name) . ' ';
my $field_names = '(' . join(", ", (map { $_ =~ /\(.*\)/ ? $_ : ( $generator->quote($_) ) } @fields)) . ')';
if ( $type eq PRIMARY_KEY ) {
Expand All @@ -553,8 +570,8 @@ sub create_index
}
elsif ( $type eq NORMAL ) {
$index_def =
'CREATE INDEX ' . $generator->quote($name) . ' on ' . $generator->quote($table_name) . ' ' . $field_names
;
'CREATE INDEX ' . $generator->quote($name) . ' on ' . $generator->quote($table_name) . ' ' .
join ' ', grep {defined} ($index_using, $field_names, $index_where);
}
else {
warn "Unknown index type ($type) on table $table_name.\n"
Expand Down
28 changes: 28 additions & 0 deletions t/14postgres-parser.t
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ my $sql = q{
FOR EACH ROW
EXECUTE PROCEDURE foo();

CREATE INDEX test_index1 ON t_test1 (f_varchar);

CREATE INDEX test_index2 ON t_test1 USING hash (f_char, f_bool);

CREATE INDEX test_index3 ON t_test1 USING hash (f_bigint, f_tz) WHERE f_bigint = '1' AND f_tz IS NULL;

alter table t_test1 add f_fk2 integer;

alter table only t_test1 add constraint c_u1 unique (f_varchar);
Expand Down Expand Up @@ -350,4 +356,26 @@ is( $trigger->perform_action_when, 'before', "Correct time for trigger");
is( $trigger->scope, 'row', "Correct scope for trigger");
is( $trigger->action, 'EXECUTE PROCEDURE foo()', "Correct action for trigger");

# test index
my @indices = $t1->get_indices;
is(scalar @indices, 3, 'got three indexes');

my $t1_i1 = $indices[0];
is( $t1_i1->name, 'test_index1', 'First index is "test_index1"' );
is( join(',', $t1_i1->fields), 'f_varchar', 'Index is on field "f_varchar"' );
is( join(',', map { keys %$_ } $t1_i1->options), '', 'Index is has no options' );

my $t1_i2 = $indices[1];
is( $t1_i2->name, 'test_index2', 'Second index is "test_index2"' );
is( join(',', $t1_i2->fields), 'f_char,f_bool', 'Index is on fields "f_char, f_bool"' );
is( join(',', map { keys %$_ } $t1_i2->options), 'using', 'Index is has one option' );
is( $t1_i2->options->[0]->{using}, 'hash', 'Index is using HASH method' );

my $t1_i3 = $indices[2];
is( $t1_i3->name, 'test_index3', 'Third index is "test_index3"' );
is( join(',', $t1_i3->fields), 'f_bigint,f_tz', 'Index is on fields "f_bigint, f_tz"' );
is( join(',', map { keys %$_ } $t1_i3->options), 'using,where', 'Index is has both options' );
is( $t1_i3->options->[0]->{using}, 'hash', 'Index is using HASH method' );
is( $t1_i3->options->[1]->{where}, "f_bigint = '1' AND f_tz IS NULL", 'Index predicate is right' );

done_testing;
8 changes: 8 additions & 0 deletions t/47postgres-producer.t
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,14 @@ is($view2_sql1, $view2_sql_replace, 'correct "CREATE OR REPLACE VIEW" SQL 2');
($def) = SQL::Translator::Producer::PostgreSQL::create_constraint($constr, $quote);
is($def->[0], 'CONSTRAINT "constr" UNIQUE ("bar", lower(foo))', 'constraint created w/ quotes');
}

{
my $index = $table->add_index(name => 'myindex', options => [{using => 'hash'}, {where => "upper(foo) = 'bar' AND bar = 'foo'"}], fields => ['bar', 'lower(foo)']);
my ($def) = SQL::Translator::Producer::PostgreSQL::create_index($index);
is($def, "CREATE INDEX myindex on foobar USING hash (bar, lower(foo)) WHERE upper(foo) = 'bar' AND bar = 'foo'", 'index using & where created');
($def) = SQL::Translator::Producer::PostgreSQL::create_index($index, $quote);
is($def, 'CREATE INDEX "myindex" on "foobar" USING hash ("bar", lower(foo)) WHERE upper(foo) = \'bar\' AND bar = \'foo\'', 'index using & where created w/ quotes');
}
}

my $drop_view_opts1 = { add_drop_view => 1, no_comments => 1, postgres_version => 8.001 };
Expand Down