qr/^no pg_hba.conf entry for/,
);
-my $sql_prettified;
+my $sql_prettified = pgFormatter::Beautify->new('colorize' => 1, 'format' => 'html');
# Do not display data in pie where percentage is lower than this value
# to avoid label overlapping.
}
else
{
- # Create instance to prettify SQL query
- if (!$noprettify)
- {
- $sql_prettified = pgFormatter::Beautify->new();
- }
&dump_as_html('.', $db);
}
$fh->close;
localdie("FATAL: can't write to $tmp_dir/$bpath/$current_out_file, $!\n");
}
# Create instance to prettify SQL query
- if (!$noprettify) {
- $sql_prettified = pgFormatter::Beautify->new();
- }
&dump_as_html('../../..', $db);
$fh->close;
}
localdie("FATAL: can't write to $tmp_dir/$wdir/$current_out_file, $!\n");
}
# Create instance to prettify SQL query
- if (!$noprettify) {
- $sql_prettified = pgFormatter::Beautify->new();
- }
&dump_as_html('../..', $db);
$fh->close;
}
$sql_prettified->beautify();
$code = $sql_prettified->content();
}
-
return $code if ($nohighlight);
- my $i = 0;
- my @qqcode = ();
- while ($code =~ s/("[^\"]*")/QQCODEY${i}A/s) {
- push(@qqcode, $1);
- $i++;
- }
- $i = 0;
- my @qcode = ();
- while ($code =~ s/('[^\']*')/QCODEY${i}B/s) {
- push(@qcode, $1);
- $i++;
- }
-
- foreach my $x (sort keys %{ $sql_prettified->{ 'dict' }->{ 'symbols' } }) {
- $code =~ s/\Q$x\E/\$\$PGBGYA\$\$$sql_prettified->{ 'dict' }->{ 'symbols' }{$x}\$\$PGBGYB\$\$/gs;
- }
- for (my $x = 0 ; $x <= $#{ $sql_prettified->{ 'dict' }->{ 'pg_keywords' } } ; $x++) {
- $code =~ s/(?<!(?-i)PGBGYB\$\$)\b$sql_prettified->{ 'dict' }->{ 'pg_keywords' }[$x]\b/<span class="kw1">$sql_prettified->{ 'dict' }->{ 'pg_keywords' }[$x]<\/span>/igs;
- }
-
- for (my $x = 0 ; $x <= $#{ $sql_prettified->{ 'dict' }->{ 'pg_functions' } } ; $x++) {
- $code =~ s/(?<!:)\b$sql_prettified->{ 'dict' }->{ 'pg_functions' }[$x]\b/<span class="kw2">$sql_prettified->{ 'dict' }->{ 'pg_functions' }[$x]<\/span>/igs;
- }
- for (my $x = 0 ; $x <= $#{ $sql_prettified->{ 'dict' }->{ 'copy_keywords' } } ; $x++) {
- $code =~ s/\b$sql_prettified->{ 'dict' }->{ 'copy_keywords' }[$x]\b/<span class="kw3">$sql_prettified->{ 'dict' }->{ 'copy_keywords' }[$x]<\/span>/igs;
- }
- for (my $x = 0 ; $x <= $#{ $sql_prettified->{ 'dict' }->{ 'brackets' } } ; $x++) {
- $code =~ s/(\Q$sql_prettified->{ 'dict' }->{ 'brackets' }[$x]\E)/<span class="br0">$1<\/span>/igs;
- }
-
- $code =~ s/\$\$PGBGYA\$\$([^\$]+)\$\$PGBGYB\$\$/<span class="sy0">$1<\/span>/gs;
-
- $code =~ s/\b(\d+)\b/<span class="nu0">$1<\/span>/igs;
-
- for (my $x = 0; $x <= $#qcode; $x++) {
- $code =~ s/QCODEY${x}B/$qcode[$x]/s;
- }
- for (my $x = 0; $x <= $#qqcode; $x++) {
- $code =~ s/QQCODEY${x}A/$qqcode[$x]/s;
- }
-
- $code =~ s/('[^']*')/<span class="st0">$1<\/span>/gs;
- $code =~ s/(`[^`]*`)/<span class="st0">$1<\/span>/gs;
-
- $code =~ s/\$\$PGBGY(A|B)\$\$//gs;
-
return encode('UTF-8', $code);
}
use warnings qw( FATAL );
use Encode qw( decode );
+use Text::Wrap;
+
+our $DEBUG = 0;
+
# PostgreSQL functions that use a FROM clause
our @have_from_clause = qw( extract overlay substring trim );
=head1 VERSION
-Version 3.0
+Version 4.0
=cut
# Version of pgFormatter
-our $VERSION = '3.0';
+our $VERSION = '4.1dev';
# Inclusion of code from Perl package SQL::Beautify
# Copyright (C) 2009 by Jonas Kramer
$beautifier->beautify();
my $nice_anonymized_html = $beautifier->content();
+ $beautifier->format();
+ $beautifier->beautify();
+ $beautifier->wrap_lines()
+ my $wrapped_txt = $beautifier->content();
+
=head1 FUNCTIONS
=head2 new
=item * wrap - wraps given keywords in pre- and post- markup. Specific docs in SQL::Beautify
+=item * format_type - try an other formatting
+
+=item * wrap_limit - wrap queries at a certain length
+
+=item * wrap_after - number of column after which lists must be wrapped
+
=back
For defaults, please check function L<set_defaults>.
my $self = bless {}, $class;
$self->set_defaults();
- for my $key ( qw( query spaces space break wrap keywords functions rules uc_keywords uc_functions no_comments placeholder separator comma comma_break format colorize) ) {
- $self->{ $key } = $options{ $key } if defined $options{ $key };
+ for my $key ( qw( query spaces space break wrap keywords functions rules uc_keywords uc_functions no_comments placeholder separator comma comma_break format colorize format_type wrap_limit wrap_after) ) {
+ $self->{ $key } = $options{ $key } if defined $options{ $key };
}
+ $self->_refresh_functions_re();
+
# Make sure "break" is sensible
$self->{ 'break' } = ' ' if $self->{ 'spaces' } == 0;
# Check comma value, when invalid set to default: end
if (lc($self->{ 'comma' }) ne 'start') {
- $self->{ 'comma' } = 'end';
+ $self->{ 'comma' } = 'end';
} else {
- $self->{ 'comma' } = lc($self->{ 'comma' });
+ $self->{ 'comma' } = lc($self->{ 'comma' });
}
$self->{ 'format' } //= 'text';
$self->{ 'colorize' } //= 1;
+ $self->{ 'format_type' } //= 0;
+ $self->{ 'wrap_limit' } //= 0;
+ $self->{ 'wrap_after' } //= 0;
+
return $self;
}
my %temp_placeholder = ();
my @temp_content = split(/(CREATE(?:\s+OR\s+REPLACE)?\s+(?:FUNCTION|PROCEDURE)\s+)/i, $self->{ 'query' });
if ($#temp_content > 0) {
- for (my $j = 0; $j <= $#temp_content; $j++) {
- next if ($temp_content[$j] =~ /^CREATE/i);
- my $fctname = '';
- if ($temp_content[$j] =~ /^([^\s\(]+)/) {
- $fctname = lc($1);
- }
- next if (!$fctname);
- my $language = 'sql';
- if ($temp_content[$j] =~ /\s+LANGUAGE\s+[']*([^'\s;]+)[']*/i) {
- $language = lc($1);
- }
- # if the function language is not SQL or PLPGSQL
- if ($language !~ /^(?:plpg)sql$/) {
- # Try to find the code separator
- my $tmp_str = $temp_content[$j];
- while ($tmp_str =~ s/\s+AS\s+([^\s]+)\s+//is) {
- my $code_sep = quotemeta($1);
+ for (my $j = 0; $j <= $#temp_content; $j++) {
+ next if ($temp_content[$j] =~ /^CREATE/i);
+ # Remove any call too CREATE/DROP LANGUAGE to not break search of function code separator
+ $temp_content[$j] =~ s/(CREATE|DROP)\s+LANGUAGE\s+[^;]+;.*//is;
+ # Fix case where code separator with $ is associated to begin/end keywords
+ $temp_content[$j] =~ s/([^\s]+\$)(BEGIN\s)/$1 $2/igs;
+ $temp_content[$j] =~ s/(\sEND)(\$[^\s]+)/$1 $2/igs;
+ $temp_content[$j] =~ s/(CREATE|DROP)\s+LANGUAGE\s+[^;]+;.*//is;
+ my $fctname = '';
+ if ($temp_content[$j] =~ /^([^\s\(]+)/) {
+ $fctname = lc($1);
+ }
+ next if (!$fctname);
+ my $language = 'sql';
+ if ($temp_content[$j] =~ /\s+LANGUAGE\s+[']*([^'\s;]+)[']*/i) {
+ $language = lc($1);
+ }
+ # if the function language is not SQL or PLPGSQL
+ if ($language !~ /^(?:plpg)?sql$/) {
+ # Try to find the code separator
+ my $tmp_str = $temp_content[$j];
+ while ($tmp_str =~ s/\s+AS\s+([^\s]+)\s+//is) {
+ my $code_sep = quotemeta($1);
foreach my $k (@{ $self->{ 'keywords' } }) {
- last if ($code_sep =~ s/\b$k$//i);
+ last if ($code_sep =~ s/\b$k$//i);
}
- if ($tmp_str =~ /\s+$code_sep[\s;]+/) {
- while ( $temp_content[$j] =~ s/($code_sep.*$code_sep)/CODEPART${i}CODEPART/s) {
- push(@{ $self->{ 'placeholder_values' } }, $1);
- $i++;
- }
- last;
- }
- }
- }
- }
+ next if (!$code_sep);
+ if ($tmp_str =~ /\s+$code_sep[\s;]+/) {
+ while ( $temp_content[$j] =~ s/($code_sep(?:.+?)$code_sep)/CODEPART${i}CODEPART/s) {
+ push(@{ $self->{ 'placeholder_values' } }, $1);
+ $i++;
+ }
+ last;
+ }
+ }
+ }
+ }
}
$self->{ 'query' } = join('', @temp_content);
# Store values of code that must not be changed following the given placeholder
if ($self->{ 'placeholder' }) {
- while ( $self->{ 'query' } =~ s/($self->{ 'placeholder' })/PLACEHOLDER${i}PLACEHOLDER/) {
- push(@{ $self->{ 'placeholder_values' } }, $1);
- $i++;
+ while ( $self->{ 'query' } =~ s/($self->{ 'placeholder' })/PLACEHOLDER${i}PLACEHOLDER/) {
+ push(@{ $self->{ 'placeholder_values' } }, $1);
+ $i++;
}
}
# Replace dynamic code with placeholder
$self->_remove_dynamic_code( \$self->{ 'query' }, $self->{ 'separator' } );
+ # Replace operator with placeholder
+ $self->_quote_operator( \$self->{ 'query' } );
+
return $self->{ 'query' };
}
=cut
-sub content {
+sub content
+{
my $self = shift;
my $new_value = shift;
$self->{ 'content' } = $new_value if defined $new_value;
-
- # Hide comment beside a placeholder for easy parsing: OBSOLETE
- #$self->_remove_comments( \$self->{ 'content' } );
+ $self->{ 'content' } =~ s/\(\s+\(/\(\(/gs;
# Replace placeholders with their original dynamic code
$self->_restore_dynamic_code( \$self->{ 'content' } );
- # Restore comments inplace: OBSOLETE
- #$self->_restore_comments(\$self->{ 'content' });
+ # Replace placeholders with their original operator
+ $self->_restore_operator( \$self->{ 'content' } );
# Replace placeholders by their original values
if ($#{ $self->{ 'placeholder_values' } } >= 0)
{
- $self->{ 'content' } =~ s/PLACEHOLDER(\d+)PLACEHOLDER/$self->{ 'placeholder_values' }[$1]/igs;
- $self->{ 'content' } =~ s/CODEPART(\d+)CODEPART/$self->{ 'placeholder_values' }[$1]/igs;
+ $self->{ 'content' } =~ s/PLACEHOLDER(\d+)PLACEHOLDER/$self->{ 'placeholder_values' }[$1]/igs;
+ $self->{ 'content' } =~ s/CODEPART(\d+)CODEPART/$self->{ 'placeholder_values' }[$1]/igs;
}
return $self->{ 'content' };
=cut
-sub highlight_code {
+sub highlight_code
+{
my ($self, $token, $last_token, $next_token) = @_;
# Do not use uninitialized variable
# Colorize operators
while ( my ( $k, $v ) = each %{ $self->{ 'dict' }->{ 'symbols' } } ) {
- if ($token eq $k) {
- $token = '<span class="sy0">' . $v . '</span>';
- return $token;
- }
+ if ($token eq $k) {
+ $token = '<span class="sy0">' . $v . '</span>';
+ return $token;
+ }
}
- # lowercase/uppercase keywords
- if ( $self->_is_keyword( $token ) ) {
- if ( $self->{ 'uc_keywords' } == 1 ) {
- $token = '<span class="kw1_l">' . $token . '</span>';
- } elsif ( $self->{ 'uc_keywords' } == 2 ) {
- $token = '<span class="kw1_u">' . $token . '</span>';
- } elsif ( $self->{ 'uc_keywords' } == 3 ) {
- $token = '<span class="kw1_c">' . $token . '</span>';
- } else {
- $token = '<span class="kw1">' . $token . '</span>';
- }
- return $token;
+ # lowercase/uppercase keywords taking care of function with same name
+ if ( $self->_is_keyword( $token ) && (!$self->_is_function( $token ) || $next_token ne '(') ) {
+ if ( $self->{ 'uc_keywords' } == 1 ) {
+ $token = '<span class="kw1_l">' . $token . '</span>';
+ } elsif ( $self->{ 'uc_keywords' } == 2 ) {
+ $token = '<span class="kw1_u">' . $token . '</span>';
+ } elsif ( $self->{ 'uc_keywords' } == 3 ) {
+ $token = '<span class="kw1_c">' . $token . '</span>';
+ } else {
+ $token = '<span class="kw1">' . $token . '</span>';
+ }
+ return $token;
}
- # lowercase/uppercase known functions or words followed by an open parenthesis if the token is not an open parenthesis
- if ($self->_is_function( $token ) || (!$self->_is_keyword( $token ) && $next_token eq '(' && $token ne '(' && !$self->_is_comment( $token )) ) {
- if ($self->{ 'uc_functions' } == 1) {
- $token = '<span class="kw2_l">' . $token . '</span>';
- } elsif ($self->{ 'uc_functions' } == 2) {
- $token = '<span class="kw2_u">' . $token . '</span>';
- } elsif ($self->{ 'uc_functions' } == 3) {
- $token = '<span class="kw2_c">' . $token . '</span>';
- } else {
- $token = '<span class="kw2">' . $token . '</span>';
- }
- return $token;
+ # lowercase/uppercase known functions or words followed by an open parenthesis
+ # if the token is not a keyword, an open parenthesis or a comment
+ if (($self->_is_function( $token ) && $next_token eq '(')
+ || (!$self->_is_keyword( $token ) && !$next_token eq '('
+ && $token ne '(' && !$self->_is_comment( $token )) ) {
+ if ($self->{ 'uc_functions' } == 1) {
+ $token = '<span class="kw2_l">' . $token . '</span>';
+ } elsif ($self->{ 'uc_functions' } == 2) {
+ $token = '<span class="kw2_u">' . $token . '</span>';
+ } elsif ($self->{ 'uc_functions' } == 3) {
+ $token = '<span class="kw2_c">' . $token . '</span>';
+ } else {
+ $token = '<span class="kw2">' . $token . '</span>';
+ }
+ return $token;
}
# Colorize STDIN/STDOUT in COPY statement
if ( grep(/^\Q$token\E$/i, @{ $self->{ 'dict' }->{ 'copy_keywords' } }) ) {
- if ($self->{ 'uc_keywords' } == 1) {
- $token = '<span class="kw3_!">' . $token . '</span>';
- } elsif ($self->{ 'uc_keywords' } == 2) {
- $token = '<span class="kw3_u">' . $token . '</span>';
- } elsif ($self->{ 'uc_keywords' } == 3) {
- $token = '<span class="kw3_c">' . $token . '</span>';
- } else {
- $token = '<span class="kw3">' . $token . '</span>';
- }
- return $token;
+ if ($self->{ 'uc_keywords' } == 1) {
+ $token = '<span class="kw3_!">' . $token . '</span>';
+ } elsif ($self->{ 'uc_keywords' } == 2) {
+ $token = '<span class="kw3_u">' . $token . '</span>';
+ } elsif ($self->{ 'uc_keywords' } == 3) {
+ $token = '<span class="kw3_c">' . $token . '</span>';
+ } else {
+ $token = '<span class="kw3">' . $token . '</span>';
+ }
+ return $token;
}
# Colorize parenthesis
if ( grep(/^\Q$token\E$/i, @{ $self->{ 'dict' }->{ 'brackets' } }) ) {
- $token = '<span class="br0">' . $token . '</span>';
- return $token;
+ $token = '<span class="br0">' . $token . '</span>';
+ return $token;
}
# Colorize comment
if ( $self->_is_comment( $token ) ) {
- $token = '<span class="br1">' . $token . '</span>';
- return $token;
+ $token = '<span class="br1">' . $token . '</span>';
+ return $token;
}
# Colorize numbers
my $query = $self->query();
my $re = qr{
- (
- (?:\\(?:copyright|errverbose|g|gx|gexec|gset|q|crosstabview|watch|\?|h|e|ef|ev|p|r|s|w|copy|echo|i|ir|o|qecho|if|elif|else|endif|d(?:[aAbcCdDfFgilLmnoOpstTuvExy]|dp|et|es|eu|ew|fa|fn|ft|fw|Fd|Fp|Ft|rds|Rp|Rs)?S?\+?|l\+?|sf\+?|sv\+?|z|a|C|f|H|pset|t|T|x|c|connect|encoding|password|conninfo|cd|setenv|timing|\!|prompt|set|unset|lo_export|lo_import|lo_list|lo_unlink))(?:$|[\n]|[\ \t](?:(?!\\\\)[\ \t\S])*) # psql meta-command
- |
- (?:--)[\ \t\S]* # single line comments
- |
- (?:\-\|\-) # range operator "is adjacent to"
- |
- (?:\->>|\->|\#>>|\#>|\?\&|\?) # Json Operators
- |
- (?:\#<=|\#>=|\#<>|\#<|\#=) # compares tinterval and reltime
- |
- (?:>>=|<<=) # inet operators
- |
- (?:!!|\@\@\@) # deprecated factorial and full text search operators
- |
- (?:\|\|\/|\|\/) # square root and cube root
- |
- (?:\@\-\@|\@\@|\#\#|<\->|<<\||\|>>|\&<\||\&<|\|\&>|\&>|<\^|>\^|\?\#|\#|\?<\||\?\-\||\?\-|\?\|\||\?\||\@>|<\@|\~=)
- # Geometric Operators
- |
- (?:~<=~|~>=~|~>~|~<~) # string comparison for pattern matching operator families
- |
- (?:!~~|!~~\*|~~\*|~~) # LIKE operators
- |
- (?:!~\*|!~|~\*) # regular expression operators
- |
- (?:\*=|\*<>|\*<=|\*>=|\*<|\*>) # composite type comparison operators
- |
- (?:<>|<=>|>=|<=|==|!=|:=|=|!|<<|>>|<|>|\|\||\||&&|&|-|\+|\*(?!/)|/(?!\*)|\%|~|\^|\?) # operators and tests
- |
- [\[\]\(\),;.] # punctuation (parenthesis, comma)
- |
- E\'\'(?!\') # empty single escaped quoted string
- |
- \'\'(?!\') # empty single quoted string
- |
- \"\"(?!\"") # empty double quoted string
- |
- "(?>(?:(?>[^"\\]+)|""|\\.)*)+" # anything inside double quotes, ungreedy
- |
- `(?>(?:(?>[^`\\]+)|``|\\.)*)+` # anything inside backticks quotes, ungreedy
- |
- E'(?>(?:(?>[^'\\]+)|''|\\.)*)+' # anything escaped inside single quotes, ungreedy.
- |
- '(?>(?:(?>[^'\\]+)|''|\\.)*)+' # anything inside single quotes, ungreedy.
- |
- /\*[\ \t\r\n\S]*?\*/ # C style comments
- |
- (?:[\w:@]+(?:\.(?:\w+|\*)?)*) # words, standard named placeholders, db.table.*, db.*
- |
- (?:\$\w+\$)
- |
- (?: \$_\$ | \$\d+ | \${1,2} | \$\w+\$ ) # dollar expressions - eg $_$ $3 $$ $BODY$
- |
- \n # newline
- |
- [\t\ ]+ # any kind of white spaces
- )
+ (
+ (?:\\(?:copyright|errverbose|g|gx|gexec|gset|q|crosstabview|watch|\?|h|e|ef|ev|p|r|s|w|copy|echo|i|ir|o|qecho|if|elif|else|endif|d(?:[aAbcCdDfFgilLmnoOpstTuvExy]|dp|et|es|eu|ew|fa|fn|ft|fw|Fd|Fp|Ft|rds|Rp|Rs)?S?\+?|l\+?|sf\+?|sv\+?|z|a|C|f|H|pset|t|T|x|c|connect|encoding|password|conninfo|cd|setenv|timing|\!|prompt|set|unset|lo_export|lo_import|lo_list|lo_unlink))(?:$|[\n]|[\ \t](?:(?!\\\\)[\ \t\S])*) # psql meta-command
+ |
+ (?:\s*--)[\ \t\S]* # single line comments
+ |
+ (?:\-\|\-) # range operator "is adjacent to"
+ |
+ (?:\->>|\->|\#>>|\#>|\?\&|\?) # Json Operators
+ |
+ (?:\#<=|\#>=|\#<>|\#<|\#=) # compares tinterval and reltime
+ |
+ (?:>>=|<<=) # inet operators
+ |
+ (?:!!|\@\@\@) # deprecated factorial and full text search operators
+ |
+ (?:\|\|\/|\|\/) # square root and cube root
+ |
+ (?:\@\-\@|\@\@|\#\#|<\->|<<\||\|>>|\&<\||\&<|\|\&>|\&>|<\^|>\^|\?\#|\#|\?<\||\?\-\||\?\-|\?\|\||\?\||\@>|<\@|\~=)
+ # Geometric Operators
+ |
+ (?:~<=~|~>=~|~>~|~<~) # string comparison for pattern matching operator families
+ |
+ (?:!~~|!~~\*|~~\*|~~) # LIKE operators
+ |
+ (?:!~\*|!~|~\*) # regular expression operators
+ |
+ (?:\*=|\*<>|\*<=|\*>=|\*<|\*>) # composite type comparison operators
+ |
+ (?:<>|<=>|>=|<=|=>|==|!=|:=|=|!|<<|>>|<|>|\|\||\||&&|&|-|\+|\*(?!/)|/(?!\*)|\%|~|\^|\?) # operators and tests
+ |
+ [\[\]\(\),;.] # punctuation (parenthesis, comma)
+ |
+ E\'\'(?!\') # empty single escaped quoted string
+ |
+ \'\'(?!\') # empty single quoted string
+ |
+ \"\"(?!\"") # empty double quoted string
+ |
+ "(?>(?:(?>[^"\\]+)|""|\\.)*)+" # anything inside double quotes, ungreedy
+ |
+ `(?>(?:(?>[^`\\]+)|``|\\.)*)+` # anything inside backticks quotes, ungreedy
+ |
+ E'(?>(?:(?>[^'\\]+)|''|\\.)*)+' # anything escaped inside single quotes, ungreedy.
+ |
+ '(?>(?:(?>[^'\\]+)|''|\\.)*)+' # anything inside single quotes, ungreedy.
+ |
+ /\*[\ \t\r\n\S]*?\*/ # C style comments
+ |
+ (?:[\w:\@]+[\$]*[\w:\@]*(?:\.(?:\w+|\*)?)*) # words, standard named placeholders, db.table.*, db.*
+ |
+ (?:\$\w+\$)
+ |
+ (?: \$_\$ | \$\d+ | \${1,2} | \$\w+\$ ) # dollar expressions - eg $_$ $3 $$ $BODY$
+ |
+ \n # newline
+ |
+ [\t\ ]+ # any kind of white spaces
+ )
}smx;
my @query = ();
# Main variables used to store differents state
$self->content( '' );
+ $self->{ '_level' } = 0;
$self->{ '_level_stack' } = [];
$self->{ '_level_parenthesis' } = [];
$self->{ '_new_line' } = 1;
$self->{ '_fct_code_delimiter' } = '';
$self->{ '_first_when_in_case' } = 0;
- $self->{ '_has_from' } = 0;
+ $self->{ '_is_in_conversion' } = 0;
$self->{ '_is_in_case' } = 0;
$self->{ '_is_in_where' } = 0;
$self->{ '_is_in_from' } = 0;
$self->{ '_is_in_join' } = 0;
$self->{ '_is_in_create' } = 0;
+ $self->{ '_is_in_rule' } = 0;
+ $self->{ '_is_in_create_function' } = 0;
+ $self->{ '_is_in_alter' } = 0;
+ $self->{ '_is_in_trigger' } = 0;
+ $self->{ '_is_in_publication' } = 0;
+ $self->{ '_is_in_call' } = 0;
$self->{ '_is_in_type' } = 0;
$self->{ '_is_in_declare' } = 0;
$self->{ '_is_in_block' } = -1;
+ $self->{ '_is_in_work' } = 0;
$self->{ '_is_in_function' } = 0;
+ $self->{ '_is_in_procedure' } = 0;
$self->{ '_is_in_index' } = 0;
$self->{ '_is_in_with' } = 0;
+ $self->{ '_is_in_explain' } = 0;
$self->{ '_parenthesis_level' } = 0;
$self->{ '_parenthesis_function_level' } = 0;
$self->{ '_has_order_by' } = 0;
$self->{ '_has_over_in_join' } = 0;
+ $self->{ '_insert_values' } = 0;
+ $self->{ '_is_in_constraint' } = 0;
+ $self->{ '_is_in_distinct' } = 0;
+ $self->{ '_is_in_array' } = 0;
+ $self->{ '_is_in_filter' } = 0;
+ $self->{ '_parenthesis_filter_level' } = 0;
+ $self->{ '_is_in_within' } = 0;
+ $self->{ '_is_in_grouping' } = 0;
+ $self->{ '_is_in_partition' } = 0;
+ $self->{ '_is_in_over' } = 0;
+ $self->{ '_is_in_policy' } = 0;
+ $self->{ '_is_in_using' } = 0;
+ $self->{ '_and_level' } = 0;
+ $self->{ '_col_count' } = 0;
+ $self->{ '_is_in_drop' } = 0;
+ $self->{ '_is_in_operator' } = 0;
+ $self->{ '_is_in_exception' } = 0;
+ $self->{ '_is_in_sub_query' } = 0;
+ $self->{ '_is_in_fetch' } = 0;
+ $self->{ '_is_in_aggregate' } = 0;
+ $self->{ '_is_in_value' } = 0;
+ $self->{ '_parenthesis_level_value' } = 0;
my $last = '';
my @token_array = $self->tokenize_sql();
- while ( defined( my $token = $self->_token ) ) {
- my $rule = $self->_get_rule( $token );
-
- ####
- # Find if the current keyword is a known function name
- ####
- if (defined $last && $last && defined $self->_next_token and $self->_next_token eq '(') {
- my $word = $token;
- $word =~ s/^[^\.]+\.//;
- if ($word && grep(/^\Q$word\E$/i, @{$self->{ 'dict' }->{ 'pg_functions' }})) {
- $self->{ '_is_in_function' }++;
+ while ( defined( my $token = $self->_token ) )
+ {
+ my $rule = $self->_get_rule( $token );
+
+ # Replace concat operator found in some SGBD into || for normalization
+ if (lc($token) eq 'concat' && defined $self->_next_token() && $self->_next_token ne '(') {
+ $token = '||';
+ }
+
+ ####
+ # Find if the current keyword is a known function name
+ ####
+ if (defined $last && $last && defined $self->_next_token and $self->_next_token eq '(') {
+ my $word = lc($token);
+ $word =~ s/^[^\.]+\.//;
+ $word =~ s/^:://;
+ if (uc($last) eq 'FUNCTION' and $token =~ /^\d+$/) {
+ $self->{ '_is_in_function' }++;
+ } elsif ($word && exists $self->{ 'dict' }->{ 'pg_functions' }{$word}) {
+ $self->{ '_is_in_function' }++;
+ # Try to detect user defined functions
+ } elsif ($last ne '*' and !$self->_is_keyword($token)
+ and (exists $self->{ 'dict' }->{ 'symbols' }{ $last }
+ or $last =~ /^\d+$/)
+ )
+ {
+ $self->{ '_is_in_function' }++;
}
- }
+ }
+
+ ####
+ # Set open parenthesis position to know if we
+ # are in subqueries or function parameters
+ ####
+ if ( $token eq ')')
+ {
+ $self->{ '_parenthesis_filter_level' }-- if ($self->{ '_is_in_filter' } and $self->{ '_parenthesis_filter_level' });
+ $self->{ '_is_in_filter' } = 0 if (!$self->{ '_parenthesis_filter_level' });
+
+ if (!$self->{ '_is_in_function' }) {
+ $self->{ '_parenthesis_level' }-- if ($self->{ '_parenthesis_level' } > 0);
+ } else {
+ $self->{ '_parenthesis_function_level' }-- if ($self->{ '_parenthesis_function_level' } > 0);
+ if (!$self->{ '_parenthesis_function_level' }) {
+ $self->{ '_level' } = pop(@{ $self->{ '_level_parenthesis_function' } }) || 0;
+ $self->_over($token,$last) if (!$self->{ '_is_in_operator' } && !$self->{ '_is_in_alter' });
+ }
+ }
+ $self->{ '_is_in_function' } = 0 if (!$self->{ '_parenthesis_function_level' });
- ####
- # Set open parenthesis position to know if we
- # are in subqueries or function parameters
- ####
- if ( $token eq ')')
- {
- if (!$self->{ '_is_in_function' }) {
- $self->{ '_parenthesis_level' }--;
- } else {
- $self->{ '_parenthesis_function_level' }--;
+ if (!$self->{ '_parenthesis_level' } && $self->{ '_is_in_sub_query' }) {
+ $self->{ '_is_in_sub_query' }--;
+ $self->_back($token, $last);
}
- $self->{ '_is_in_function' } = 0 if (!$self->{ '_parenthesis_function_level' });
- }
- elsif ( $token eq '(')
- {
- if ($self->{ '_is_in_function' }) {
- $self->{ '_parenthesis_function_level' }++;
- } else {
- if (!$self->{ '_parenthesis_level' } && $self->{ '_is_in_from' }) {
- push(@{ $self->{ '_level_parenthesis' } } , $self->{ '_level' });
- }
- $self->{ '_parenthesis_level' }++;
+ if ($self->{ '_is_in_value' }) {
+ $self->{ '_parenthesis_level_value' }-- if ($self->{ '_parenthesis_level_value' });
}
- }
-
- ####
- # Control case where we have to add a newline, go back and
- # reset indentation after the last ) in the WITH statement
- ####
- if ($token =~ /^WITH$/i && (!defined $last || $last ne ')'))
+ }
+ elsif ( $token eq '(')
+ {
+ $self->{ '_parenthesis_filter_level' }++ if ($self->{ '_is_in_filter' });
+ if ($self->{ '_is_in_function' }) {
+ $self->{ '_parenthesis_function_level' }++;
+ push(@{ $self->{ '_level_parenthesis_function' } } , $self->{ '_level' }) if ($self->{ '_parenthesis_function_level' } == 1);
+ } else {
+ if (!$self->{ '_parenthesis_level' } && $self->{ '_is_in_from' }) {
+ push(@{ $self->{ '_level_parenthesis' } } , $self->{ '_level' });
+ }
+ $self->{ '_parenthesis_level' }++;
+ if ($self->{ '_is_in_value' }) {
+ $self->{ '_parenthesis_level_value' }++;
+ }
+ }
+
+ if (defined $self->_next_token and $self->_next_token =~ /^(SELECT|WITH)$/i) {
+ $self->{ '_is_in_sub_query' }++ if (defined $last and uc($last) ne 'AS');
+ }
+ }
+
+ ####
+ # Control case where we have to add a newline, go back and
+ # reset indentation after the last ) in the WITH statement
+ ####
+ if ($token =~ /^WITH$/i && (!defined $last || $last ne ')')
+ && !$self->{ '_is_in_partition' } && !$self->{ '_is_in_publication' }
+ && !$self->{ '_is_in_policy' })
{
- $self->{ '_is_in_with' } = 1;
+ $self->{ '_is_in_with' } = 1 if (!$self->{ '_is_in_using' } && uc($self->_next_token) ne 'ORDINALITY' && uc($last) ne 'START');
+ $self->{ 'no_break' } = 1 if (uc($self->_next_token) eq 'ORDINALITY');
+ }
+ elsif ($token =~ /^WITH$/i && uc($self->_next_token) eq 'ORDINALITY')
+ {
+ $self->{ 'no_break' } = 1;
}
- elsif ($token =~ /^(AS|IS)$/i && defined $self->_next_token && $self->_next_token eq '(')
+ elsif ($token =~ /^(AS|IS)$/i && defined $self->_next_token && $self->_next_token eq '(')
{
- $self->{ '_is_in_with' }++ if ($self->{ '_is_in_with' } == 1);
+ $self->{ '_is_in_with' }++ if ($self->{ '_is_in_with' } == 1);
+ }
+ elsif ($self->{ '_is_in_create' } && $token =~ /^AS$/i && defined $self->_next_token && uc($self->_next_token) eq 'SELECT')
+ {
+ $self->{ '_is_in_create' } = 0;
+ }
+ elsif ( $token eq '[' )
+ {
+ $self->{ '_is_in_array' }++;
+ }
+ elsif ( $token eq ']' )
+ {
+ $self->{ '_is_in_array' }-- if ($self->{ '_is_in_array' });
}
- elsif ( $token eq ')' )
+ elsif ( $token eq ')' )
{
- $self->{ '_has_order_by' } = 0;
- $self->{ '_has_from' } = 0;
- if ($self->{ '_is_in_with' } > 1 && !$self->{ '_parenthesis_level' }) {
- $self->_new_line;
- $self->_back;
- $self->_add_token( $token );
- @{ $self->{ '_level_stack' } } = ();
- $self->{ '_level' } = 0;
- $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
- if ($self->{ '_is_in_with' }) {
- if (defined $self->_next_token && $self->_next_token eq ',') {
- $self->{ '_is_in_with' } = 1;
- } else {
- $self->{ '_is_in_with' } = 0;
- }
- }
- next;
+ $self->{ '_has_order_by' } = 0;
+ if ($self->{ '_is_in_distinct' }) {
+ $self->_add_token( $token );
+ $self->_new_line($token,$last);
+ $self->{ '_is_in_distinct' } = 0;
+ $last = $token;
+ next;
}
- }
- ####
- # Set the current kind of statement parsed
- ####
- if ($token =~ /^(FUNCTION|PROCEDURE|SEQUENCE|INSERT|DELETE|UPDATE|SELECT|RAISE|ALTER|GRANT|REVOKE)$/i) {
- my $k_stmt = uc($1);
- # Set current statement with taking care to exclude of SELECT ... FOR UPDATE statement.
- if ($k_stmt ne 'UPDATE' or (defined $self->_next_token and $self->_next_token ne ';' and $self->_next_token ne ')')) {
- $self->{ '_current_sql_stmt' } = $k_stmt if ($self->{ '_current_sql_stmt' } !~ /^(GRANT|REVOKE)$/i);
- }
- }
+ $self->{ '_is_in_using' } = 0 if ($self->{ '_is_in_using' } && !$self->{ '_parenthesis_level' });
- ####
- # Mark that we are in CREATE statement that need newline
- # after a comma in the parameter, declare or column lists.
- ####
- if ($token =~ /^CREATE$/i && $self->_next_token !~ /^(UNIQUE|INDEX|EXTENSION|TYPE)$/i) {
- $self->{ '_is_in_create' } = 1;
- } elsif ($token =~ /^CREATE$/i && $self->_next_token =~ /^TYPE$/i) {
- $self->{ '_is_in_type' } = 1;
+ if ($self->{ '_is_in_create' } > 1 and defined $self->_next_token && uc($self->_next_token) eq 'AS' && !$self->{ '_is_in_with'}) {
+ $self->_new_line($token,$last);
+ }
+ if (($self->{ '_is_in_with' } > 1 || $self->{ '_is_in_operator' }) && !$self->{ '_parenthesis_level' }
+ && !$self->{ '_is_in_alter' } && !$self->{ '_is_in_policy' }) {
+ $self->_new_line($token,$last) if (!$self->{ '_is_in_operator' } ||
+ (!$self->{ '_is_in_drop' } and $self->_next_token eq ';'));
+ if (!$self->{ '_is_in_operator' }) {
+ $self->{ '_level' } = pop(@{ $self->{ '_level_stack' } }) || 0;
+ $self->_back($token, $last);
+ }
+ $self->_add_token( $token );
+ if (!$self->{ '_is_in_operator' }) {
+ @{ $self->{ '_level_stack' } } = ();
+ $self->{ '_level' } = 0;
+ $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
+ }
+ if ($self->{ '_is_in_with' }) {
+ if (defined $self->_next_token && $self->_next_token eq ',') {
+ $self->{ '_is_in_with' } = 1;
+ } else {
+ $self->{ '_is_in_with' } = 0;
+ }
+ }
+ $last = $token;
+ next;
+ }
}
+ elsif (defined $self->_next_token && $self->_next_token eq '(')
+ {
+ $self->{ '_is_in_filter' } = 1 if (uc($token) eq 'FILTER');
+ $self->{ '_is_in_grouping' } = 1 if ($token =~ /^GROUPING|ROLLUP$/i);
+ }
+ elsif ( uc($token) eq 'PASSING' and defined $self->_next_token && uc($self->_next_token) eq 'BY')
+ {
+ $self->{ '_has_order_by' } = 1;
+ }
- ####
- # Mark that we are in index/constraint creation statement to
- # avoid inserting a newline after comma and AND/OR keywords.
- # This also used in SET statement taking care that we are not
- # in update statement. CREATE statement are not subject to this rule
- ####
- if (! $self->{ '_is_in_create' } and $token =~ /^(INDEX|PRIMARY|CONSTRAINT)$/i) {
- $self->{ '_is_in_index' } = 1;
- } elsif (! $self->{ '_is_in_create' } and uc($token) eq 'SET') {
- $self->{ '_is_in_index' } = 1 if ($self->{ '_current_sql_stmt' } ne 'UPDATE');
- }
- # Same as above but for ALTER FUNCTION/PROCEDURE/SEQUENCE or when
- # we are in a CREATE FUNCTION/PROCEDURE statement
- elsif ($token =~ /^(FUNCTION|PROCEDURE|SEQUENCE)$/i) {
- $self->{ '_is_in_index' } = 1 if (uc($last) eq 'ALTER');
- if ($token =~ /^(FUNCTION|PROCEDURE)$/i && $self->{ '_is_in_create' }) {
+ # Explain need indentation in option list
+ if ( uc($token) eq 'EXPLAIN' )
+ {
+ $self->{ '_is_in_explain' } = 1;
+ }
+
+ ####
+ # Set the current kind of statement parsed
+ ####
+ if ($token =~ /^(FUNCTION|PROCEDURE|SEQUENCE|INSERT|DELETE|UPDATE|SELECT|RAISE|ALTER|GRANT|REVOKE|COMMENT|DROP|RULE|COMMENT)$/i) {
+ my $k_stmt = uc($1);
+ $self->{ '_is_in_explain' } = 0;
+ # Set current statement with taking care to exclude of SELECT ... FOR UPDATE statement.
+ if ($k_stmt ne 'UPDATE' or (defined $self->_next_token and $self->_next_token ne ';' and $self->_next_token ne ')')) {
+ if ($k_stmt !~ /^UPDATE|DELETE$/i || !$self->{ '_is_in_create' }) {
+ $self->{ '_current_sql_stmt' } = $k_stmt if ($self->{ '_current_sql_stmt' } !~ /^(GRANT|REVOKE)$/i and !$self->{ '_is_in_trigger' } and !$self->{ '_is_in_operator' } && !$self->{ '_is_in_alter' });
+ }
+ }
+ }
+
+ ####
+ # Mark that we are in CREATE statement that need newline
+ # after a comma in the parameter, declare or column lists.
+ ####
+ if ($token =~ /^(FUNCTION|PROCEDURE)$/i and $self->{ '_is_in_create' } and !$self->{'_is_in_trigger'}) {
+ $self->{ '_is_in_create_function' } = 1;
+ } elsif ($token =~ /^(FUNCTION|PROCEDURE)$/i and $self->{'_is_in_trigger'}) {
$self->{ '_is_in_index' } = 1;
- }
- }
- # Desactivate index like formatting when RETURN(S) keyword is found
- elsif ($token =~ /^(RETURN|RETURNS)$/i) {
- $self->{ '_is_in_index' } = 0;
}
+ if ($token =~ /^CREATE$/i && $self->_next_token !~ /^(EVENT|UNIQUE|INDEX|EXTENSION|TYPE|PUBLICATION|OPERATOR|RULE|CONVERSION|DOMAIN)$/i) {
+ $self->{ '_is_in_create' } = 1;
+ } elsif ($token =~ /^CREATE$/i && $self->_next_token =~ /^RULE$/i) {
+ $self->{ '_is_in_rule' } = 1;
+ } elsif ($token =~ /^CREATE$/i && $self->_next_token =~ /^EVENT$/i) {
+ $self->{ '_is_in_trigger' } = 1;
+ } elsif ($token =~ /^CREATE$/i && $self->_next_token =~ /^TYPE$/i) {
+ $self->{ '_is_in_type' } = 1;
+ } elsif ($token =~ /^CREATE$/i && $self->_next_token =~ /^PUBLICATION$/i) {
+ $self->{ '_is_in_publication' } = 1;
+ } elsif ($token =~ /^CREATE$/i && $self->_next_token =~ /^CONVERSION$/i) {
+ $self->{ '_is_in_conversion' } = 1;
+ } elsif ($token =~ /^CREATE|DROP$/i && $self->_next_token =~ /^OPERATOR$/i) {
+ $self->{ '_is_in_operator' } = 1;
+ $self->{ '_is_in_drop' } = 1 if ($token =~ /^DROP$/i);
+ } elsif ($token =~ /^ALTER$/i) {
+ $self->{ '_is_in_alter' }++;
+ } elsif ($token =~ /^DROP$/i){
+ $self->{ '_is_in_drop' } = 1;
+ } elsif ($token =~ /^VIEW$/i and $self->{ '_is_in_create' }) {
+ $self->{ '_is_in_index' } = 1;
+ $self->{ '_is_in_create' } = 0;
+ } elsif ($token =~ /^AGGREGATE$/i and $self->{ '_is_in_create' }) {
+ $self->{ '_is_in_aggregate' } = 1;
+ $self->{ '_has_order_by' } = 1;
+ } elsif ($token =~ /^EVENT$/i && $self->_next_token =~ /^TRIGGER$/i) {
+ $self->_over($token, $last);
+ $self->{ '_is_in_index' } = 1;
+ }
+
+ if ($self->{ '_is_in_using' } and defined $self->_next_token and $self->_next_token =~ /^OPERATOR|AS$/i) {
+ $self->{ '_is_in_using' } = 0;
+ }
+
+ if ($token =~ /^ALTER$/i and $self->{ '_is_in_alter' } > 1) {
+ $self->_new_line($token,$last);
+ $self->_over($token, $last) if ($last ne ',');
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
####
- # Mark statements that use string_agg() or group_concat() function
- # as statement that can have an ORDER BY clause inside the call to
- # prevent applying order by formatting.
+ # Mark that we are in a CALL statement to remove any new line
####
- if ($token =~ /^(string_agg|group_concat)$/i) {
+ if ($token =~ /^CALL/i) {
+ $self->{ '_is_in_call' } = 1;
+ }
+
+ # Increment operator tag to add newline in alter operator statement
+ if (($self->{ '_is_in_alter' } or uc($last) eq 'AS') and uc($token) eq 'OPERATOR') {
+ $self->_new_line($token,$last) if (uc($last) eq 'AS' and uc($token) eq 'OPERATOR');
+ $self->{ '_is_in_operator' }++;
+ }
+
+ ####
+ # Mark that we are in index/constraint creation statement to
+ # avoid inserting a newline after comma and AND/OR keywords.
+ # This also used in SET statement taking care that we are not
+ # in update statement. CREATE statement are not subject to this rule
+ ####
+ if (! $self->{ '_is_in_create' } and $token =~ /^(INDEX|PRIMARY|CONSTRAINT)$/i) {
+ $self->{ '_is_in_index' } = 1;
+ } elsif (! $self->{ '_is_in_create' } and uc($token) eq 'SET') {
+ $self->{ '_is_in_index' } = 1 if ($self->{ '_current_sql_stmt' } ne 'UPDATE');
+ } elsif ($self->{ '_is_in_create' } and (uc($token) eq 'UNIQUE' or (uc($token) eq 'PRIMARY' and uc($self->_next_token) eq 'KEY'))) {
+ $self->{ '_is_in_constraint' } = 1;
+ }
+
+ # Same as above but for ALTER FUNCTION/PROCEDURE/SEQUENCE or when
+ # we are in a CREATE FUNCTION/PROCEDURE statement
+ elsif ($token =~ /^(FUNCTION|PROCEDURE|SEQUENCE)$/i and !$self->{'_is_in_trigger'}) {
+ $self->{ '_is_in_index' } = 1 if (uc($last) eq 'ALTER' and !$self->{ '_is_in_operator' } and !$self->{ '_is_in_alter' });
+ if ($token =~ /^FUNCTION$/i && ($self->{ '_is_in_create' } || $self->{ '_current_sql_stmt' } eq 'COMMENT')) {
+ $self->{ '_is_in_index' } = 1 if (!$self->{ '_is_in_operator' });
+ } elsif ($token =~ /^PROCEDURE$/i && $self->{ '_is_in_create' }) {
+ $self->{ '_is_in_index' } = 1;
+ $self->{ '_is_in_procedure' } = 1;
+ }
+ }
+ # Desactivate index like formatting when RETURN(S) keyword is found
+ elsif ($token =~ /^(RETURN|RETURNS)$/i) {
+ $self->{ '_is_in_index' } = 0;
+ } elsif ($token =~ /^AS$/i) {
+ if ( !$self->{ '_is_in_index' } and $self->{ '_is_in_from' } and $last eq ')' and uc($token) eq 'AS' and $self->_next_token() eq '(') {
+ $self->{ '_is_in_index' } = 1;
+ } else {
+ $self->{ '_is_in_index' } = 0;
+ }
+ $self->{ '_is_in_block' } = 1 if ($self->{ '_is_in_procedure' });
+ $self->{ '_is_in_over' } = 0;
+ }
+ if ($token =~ /^BEGIN|DECLARE$/i) {
+ $self->{ '_is_in_create' }-- if ($self->{ '_is_in_create' });
+ }
+
+ ####
+ # Mark statements that use string_agg() or group_concat() function
+ # as statement that can have an ORDER BY clause inside the call to
+ # prevent applying order by formatting.
+ ####
+ if ($token =~ /^(string_agg|group_concat|array_agg|percentile_cont)$/i) {
+ $self->{ '_has_order_by' } = 1;
+ } elsif ( $token =~ /^(?:GENERATED)$/i and $self->_next_token =~ /^ALWAYS|BY$/i ) {
+ $self->{ 'no_break' } = 1;
+ } elsif ( $token =~ /^(?:TRUNCATE)$/i ) {
+ $self->{ 'no_break' } = 1;
+ } elsif ( uc($token) eq 'IDENTITY' ) {
+ $self->{ '_has_order_by' } = 0;
+ $self->{ 'no_break' } = 0;
+ } elsif ( $self->{ '_has_order_by' } and uc($token) eq 'ORDER' and $self->_next_token =~ /^BY$/i) {
+ $self->_add_token( $token, $last );
+ $last = $token;
+ next;
+ } elsif ($self->{ '_has_order_by' } and uc($token) eq 'BY') {
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
+ elsif ($token =~ /^OVER$/i)
+ {
+ $self->_add_token( $token );
+ $self->{ '_is_in_over' } = 1;
$self->{ '_has_order_by' } = 1;
- } elsif ( $self->{ '_has_order_by' } and uc($token) eq 'ORDER' and $self->_next_token =~ /^BY$/i) {
- $self->_add_token( $token );
- $last = $token;
- next;
- } elsif ($self->{ '_has_order_by' } and uc($token) eq 'BY') {
- $self->_add_token( $token );
- $self->{ '_has_order_by' } = 0;
- next;
+ $last = $token;
+ next;
}
- ####
- # Set function code delimiter, it can be any string found after
- # the AS keyword in function or procedure creation code
- ####
- # Toogle _fct_code_delimiter to force next token to be stored as the function code delimiter
- if (uc($token) eq 'AS' and (!$self->{ '_fct_code_delimiter' } || $self->_next_token =~ /CODEPART/)
- and $self->{ '_current_sql_stmt' } =~ /^(FUNCTION|PROCEDURE)$/i)
- {
- if ($self->{ '_is_in_create' })
+ # Fix case where we don't knwon if we are outside a SQL function
+ if (defined $last and uc($last) eq 'AS'and defined $self->_next_token and $self->_next_token eq ';'
+ and $self->{ '_is_in_create_function' }) {
+ $self->{ '_is_in_create_function' } = 0;
+ }
+
+ ####
+ # Set function code delimiter, it can be any string found after
+ # the AS keyword in function or procedure creation code
+ ####
+ # Toogle _fct_code_delimiter to force next token to be stored as the function code delimiter
+ if (uc($token) eq 'AS' and (!$self->{ '_fct_code_delimiter' } || $self->_next_token =~ /CODEPART/)
+ and $self->{ '_current_sql_stmt' } =~ /^(FUNCTION|PROCEDURE)$/i)
+ {
+ if ($self->{ '_is_in_create' })
{
- $self->_new_line;
- $self->_add_token( $token );
+ $self->_new_line($token,$last);
+ $self->_add_token( $token );
@{ $self->{ '_level_stack' } } = ();
$self->{ '_level' } = 0;
$self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
- $self->{ '_is_in_create' } = 0;
+ $self->{ '_is_in_create' } = 0;
} else {
- $self->_add_token( $token );
- }
- if ($self->_next_token !~ /CODEPART/)
+ $self->_add_token( $token );
+ }
+ if ($self->_next_token !~ /CODEPART/ || $self->_next_token =~ /^'/)
{
- $self->{ '_fct_code_delimiter' } = '1';
+ $self->{ '_fct_code_delimiter' } = '1';
}
- $self->{ '_is_in_create' } = 0;
- next;
+ $self->{ '_is_in_create' } = 0;
+ $last = $token;
+ next;
+ }
+ elsif ($token =~ /^INSTEAD$/i and defined $last and uc($last) eq 'DO')
+ {
+ $self->_add_token( $token );
+ $self->_new_line($token,$last);
+ $last = $token;
+ next;
+ }
+ elsif ($token =~ /^DO$/i and defined $self->_next_token and $self->_next_token =~ /^INSTEAD$/i)
+ {
+ $self->_new_line($token,$last);
+ $self->_over($token,$last);
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
+ elsif ($token =~ /^DO$/i and !$self->{ '_fct_code_delimiter' } and $self->_next_token =~ /^\$[^\s]*/)
+ {
+ $self->{ '_fct_code_delimiter' } = '1';
+ $self->{ '_is_in_create_function' } = 1;
+ $self->_new_line($token,$last) if ($self->{ 'content' } !~ /\n$/s);
+ $self->_add_token( $token );
+ $last = $token;
+ next;
}
- # Store function code delimiter
- if ($self->{ '_fct_code_delimiter' } eq '1')
+ # Store function code delimiter
+ if ($self->{ '_fct_code_delimiter' } eq '1')
{
if ($self->_next_token =~ /CODEPART/) {
- $self->{ '_fct_code_delimiter' } = '0';
+ $self->{ '_fct_code_delimiter' } = '0';
} else {
- $self->{ '_fct_code_delimiter' } = $token;
+ $self->{ '_fct_code_delimiter' } = $token;
}
- $self->_add_token( $token );
- $last = $token;
- $self->_new_line;
- $self->_over if (defined $self->_next_token && $self->_next_token !~ /^(DECLARE|BEGIN)$/i);
- next;
- }
-
- # Desactivate the block mode when code delimiter is found for the second time
- if ($self->{ '_fct_code_delimiter' } && $token eq $self->{ '_fct_code_delimiter' })
+ $self->_add_token( $token );
+ $last = $token;
+ $self->_new_line($token,$last);
+ $self->_over($token,$last) if (defined $self->_next_token && $self->_next_token !~ /^(DECLARE|BEGIN)$/i);
+ next;
+ }
+
+ # Desactivate the block mode when code delimiter is found for the second time
+ if ($self->{ '_fct_code_delimiter' } && $token eq $self->{ '_fct_code_delimiter' })
{
- $self->{ '_is_in_block' } = -1;
- @{ $self->{ '_level_stack' } } = ();
- $self->{ '_level' } = 0;
- $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
- $self->{ '_fct_code_delimiter' } = '';
- $self->{ '_current_sql_stmt' } = '';
- $self->_new_line;
- $self->_add_token( $token );
- next;
- }
-
- ####
- # Mark when we are parsing a DECLARE or a BLOCK section. When
- # entering a BLOCK section store the current indentation level
- ####
- if (uc($token) eq 'DECLARE') {
- $self->{ '_is_in_block' } = -1;
- $self->{ '_is_in_declare' } = 1;
- @{ $self->{ '_level_stack' } } = ();
- $self->{ '_level' } = 0;
- $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
- $self->_new_line;
- $self->_add_token( $token );
- $self->_new_line;
- $self->_over;
- next;
- }
- elsif ( uc($token) eq 'BEGIN' )
+ $self->{ '_is_in_block' } = -1;
+ $self->{ '_is_in_exception' } = 0;
+ @{ $self->{ '_level_stack' } } = ();
+ $self->{ '_level' } = 0;
+ $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
+ $self->{ '_fct_code_delimiter' } = '';
+ $self->{ '_current_sql_stmt' } = '';
+ $self->_new_line($token,$last);
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
+
+ ####
+ # Mark when we are parsing a DECLARE or a BLOCK section. When
+ # entering a BLOCK section store the current indentation level
+ ####
+ if (uc($token) eq 'DECLARE' and $self->{ '_is_in_create_function' }) {
+ $self->{ '_is_in_block' } = -1;
+ $self->{ '_is_in_exception' } = 0;
+ $self->{ '_is_in_declare' } = 1;
+ @{ $self->{ '_level_stack' } } = ();
+ $self->{ '_level' } = 0;
+ $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
+ $self->_new_line($token,$last);
+ $self->_add_token( $token );
+ $self->_new_line($token,$last);
+ $self->_over($token,$last);
+ $last = $token;
+ $self->{ '_is_in_create_function' } = 0;
+ next;
+ }
+ elsif ( uc($token) eq 'BEGIN' )
{
+ $self->{ '_is_in_declare' } = 0;
+ if ($self->{ '_is_in_block' } == -1) {
+ @{ $self->{ '_level_stack' } } = ();
+ $self->{ '_level' } = 0;
+ $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
+ } else {
+ # Store current indent position to print END at the right level
+ push @{ $self->{ '_level_stack' } }, $self->{ '_level' };
+ }
+ $self->_new_line($token,$last);
+ $self->_add_token( $token );
+ if (defined $self->_next_token && $self->_next_token !~ /^(WORK|TRANSACTION|ISOLATION|;)$/i) {
+ $self->_new_line($token,$last);
+ $self->_over($token,$last);
+ $self->{ '_is_in_block' }++;
+ }
+ $self->{ '_is_in_work' } = 1 if (defined $self->_next_token && $self->_next_token =~ /^(WORK|TRANSACTION|ISOLATION|;)$/i);
+ $last = $token;
+ next;
+ }
+ elsif ( $token =~ /^(COMMIT|ROLLBACK)$/i and (not defined $last or uc($last) ne 'ON'))
+ {
+ $self->{ '_is_in_work' } = 0;
$self->{ '_is_in_declare' } = 0;
- if ($self->{ '_is_in_block' } == -1) {
- @{ $self->{ '_level_stack' } } = ();
- $self->{ '_level' } = 0;
- $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
- } else {
- # Store current indent position to print END at the right level
- push @{ $self->{ '_level_stack' } }, $self->{ '_level' };
- }
- $self->_new_line;
- $self->_add_token( $token );
- if (defined $self->_next_token && $self->_next_token ne ';') {
- $self->_new_line;
- $self->_over;
- $self->{ '_is_in_block' }++;
- }
- next;
- }
-
- ####
- # Special case where we want to add a newline into ) AS (
- ####
- if (uc($token) eq 'AS' and $last eq ')' and $self->_next_token eq '(')
+ $self->_new_line($token,$last);
+ $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0;
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
+ elsif ( $token =~ /^FETCH$/i and defined $last and $last eq ';')
{
- $self->_new_line;
- }
- # and before RETURNS with increasing indent level
+ $self->_new_line($token,$last);
+ $self->_back($token, $last) if ($self->{ '_is_in_block' } == -1);
+ $self->_add_token( $token );
+ $last = $token;
+ $self->{ '_is_in_fetch' } = 1;
+ next;
+ }
+
+ ####
+ # Special case where we want to add a newline into ) AS (
+ ####
+ if (uc($token) eq 'AS' and $last eq ')' and $self->_next_token eq '(')
+ {
+ $self->_new_line($token,$last);
+ }
+ # and before RETURNS with increasing indent level
elsif (uc($token) eq 'RETURNS')
{
- $self->_new_line;
- $self->_over;
- }
+ $self->_new_line($token,$last);
+ $self->_over($token,$last);
+ }
+ # and before WINDOW
+ elsif (uc($token) eq 'WINDOW')
+ {
+ $self->_new_line($token,$last);
+ $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0;
+ $self->_add_token( $token );
+ $last = $token;
+ $self->{ '_has_order_by' } = 1;
+ next;
+ }
- if ( $rule )
+ # Treated DISTINCT as a modifier of the whole select clause, not only the first column only
+ if (uc($token) eq 'ON' && defined $last && uc($last) eq 'DISTINCT')
{
- $self->_process_rule( $rule, $token );
- }
+ $self->{ '_is_in_distinct' } = 1;
+ $self->_over($token,$last);
+ }
+ elsif (uc($token) eq 'DISTINCT' && defined $last && uc($last) eq 'SELECT' && defined $self->_next_token && $self->_next_token !~ /^ON$/i)
+ {
+ $self->_add_token( $token );
+ $self->_new_line($token,$last) if (!$self->{'wrap_after'});
+ $self->_over($token,$last);
+ $last = $token;
+ next;
+ }
- elsif ($token =~ /^(LANGUAGE|SECURITY|COST)$/i)
+ if ( $rule )
{
- $self->_new_line;
- $self->_add_token( $token );
- }
+ $self->_process_rule( $rule, $token );
+ }
- elsif ( $token eq '(' )
+ elsif ($token =~ /^(LANGUAGE|SECURITY|COST)$/i && !$self->{ '_is_in_alter' } && !$self->{ '_is_in_drop' } )
{
- $self->{ '_is_in_create' }++ if ($self->{ '_is_in_create' });
- $self->_add_token( $token, $last );
- if ( !$self->{ '_is_in_index' }) {
- if (uc($last) eq 'AS' || $self->{ '_is_in_create' } == 2 || uc($self->_next_token) eq 'CASE') {
- $self->_new_line;
- }
- if ($self->{ '_is_in_with' } == 1) {
- $self->_over;
- $self->_new_line;
- next;
- }
- $self->_over;
- if ($self->{ '_is_in_type' } == 1) {
- $last = $token;
- next;
- }
+ $self->_new_line($token,$last) if (uc($token) ne 'SECURITY' or (defined $last and uc($last) ne 'LEVEL'));
+ $self->_add_token( $token );
+ }
+ elsif ($token =~ /^PARTITION$/i && !$self->{ '_is_in_over' } && defined $last && $last ne '(')
+ {
+ $self->{ '_is_in_partition' } = 1;
+ if ($self->{ '_is_in_create' } && defined $last and $last eq ')')
+ {
+ $self->_new_line($token,$last);
+ $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0;
+ $self->_add_token( $token );
}
- }
-
- elsif ( $token eq ')' ) {
- if ($self->{ '_is_in_with' } == 1) {
- $self->_back;
- $self->_new_line;
- $self->_add_token( $token );
- next;
+ else
+ {
+ $self->_add_token( $token );
+ }
+ }
+ elsif ($token =~ /^POLICY$/i)
+ {
+ $self->{ '_is_in_policy' } = 1;
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
+ elsif ($token =~ /^TRIGGER$/i and defined $last and uc($last) eq 'CREATE')
+ {
+ $self->{ '_is_in_trigger' } = 1;
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
+ elsif ($token =~ /^(BEFORE|AFTER)$/i and $self->{ '_is_in_trigger' })
+ {
+ $self->_new_line($token,$last);
+ $self->_over($token,$last);
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
+ elsif ($token =~ /^EXECUTE$/i and ($self->{ '_is_in_trigger' } or (defined $last and uc($last) eq 'AS')))
+ {
+ $self->_new_line($token,$last);
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
+ elsif ( $token eq '(' )
+ {
+ if ($self->{ '_is_in_aggregate' } && defined $self->_next_token and ($self->_is_keyword($self->_next_token) or $self->_is_sql_keyword($self->_next_token)) and uc($self->_next_token) ne 'VARIADIC') {
+ $self->{ '_is_in_aggregate' } = 0;
+ $self->{ '_has_order_by' } = 0;
}
- if ($self->{ '_is_in_index' }) {
- $self->_add_token( '' );
- $self->_add_token( $token );
- $last = $token;
- next;
+ $self->{ '_is_in_create' }++ if ($self->{ '_is_in_create' });
+ $self->{ '_is_in_constraint' }++ if ($self->{ '_is_in_constraint' });
+ $self->_add_token( $token, $last );
+ if (defined $self->_next_token and $self->_next_token eq ')' and !$self->{ '_is_in_create' }) {
+ $last = $token;
+ next;
}
- $self->_new_line if ($self->{ '_is_in_create' } > 1
- and (not defined $self->_next_token or $self->_next_token eq ';')
- );
- $self->_new_line if ($self->{ '_is_in_type' } == 1
- and (not defined $self->_next_token or $self->_next_token eq ';')
- );
- $self->{ '_is_in_create' }-- if ($self->{ '_is_in_create' });
- $self->{ '_is_in_type' }-- if ($self->{ '_is_in_type' });
- $self->_new_line if ($self->{ '_current_sql_stmt' } ne 'INSERT'
- and !$self->{ '_is_in_function' }
- and (defined $self->_next_token
- and $self->_next_token =~ /^(SELECT|WITH)$/i)
- and $last ne ')'
- );
- $self->_back;
- $self->_add_token( $token );
- # Do not go further if this is the last token
- if (not defined $self->_next_token) {
- $last = $token;
- next;
+ if ( !$self->{ '_is_in_index' } && !$self->{ '_is_in_publication' }
+ && !$self->{ '_is_in_distinct' } && !$self->{ '_is_in_filter' }
+ && !$self->{ '_is_in_grouping' } && !$self->{ '_is_in_partition' }
+ && !$self->{ '_is_in_over' } && !$self->{ '_is_in_trigger' }
+ && !$self->{ '_is_in_policy' } && !$self->{ '_is_in_aggregate' }
+ && !$self->{ 'no_break' }
+ ) {
+ if (uc($last) eq 'AS' || $self->{ '_is_in_create' } == 2 || uc($self->_next_token) eq 'CASE')
+ {
+ $self->_new_line($token,$last) if ((!$self->{'_is_in_function'} or $self->_next_token =~ /^CASE$/i) and $self->_next_token ne ')' and $self->_next_token !~ /^(PARTITION|ORDER)$/i);
+ }
+ if ($self->{ '_is_in_with' } == 1 or $self->{ '_is_in_explain' }) {
+ $self->_over($token,$last);
+ $self->_new_line($token,$last) if (!$self->{ 'wrap_after' });
+ $last = $token if (!$self->{ '_is_in_explain' } || $self->{ 'wrap_after' });
+ next;
+ }
+ if (!$self->{ '_is_in_if' } and !$self->{ '_is_in_alter' } and (!$self->{ '_is_in_function' } or $last ne '('))
+ {
+ $self->_over($token,$last) if ($self->{ '_is_in_operator' } <= 2);
+ if (!$self->{ '_is_in_function' } and !$self->_is_type($self->_next_token)) {
+ if ($self->{ '_is_in_operator' } == 1) {
+ $self->_new_line($token,$last);
+ $self->{ '_is_in_operator' }++;
+ } elsif ($self->{ '_is_in_type' }) {
+ $self->_new_line($token,$last);
+ }
+ }
+ $last = $token;
+ }
+ if ($self->{ '_is_in_type' } == 1) {
+ $last = $token;
+ next;
+ }
+ }
+
+ if ($self->{ 'format_type' } && $self->{ '_current_sql_stmt' } =~ /FUNCTION|PROCEDURE/i
+ && $self->{ '_is_in_create' } == 2
+ && (not defined $self->_next_token or $self->_next_token ne ')')
+ ) {
+ $self->_over($token,$last) if ($self->{ '_is_in_block' } < 0);
+ $self->_new_line($token,$last);
+ next;
}
+ }
- # When closing CTE statement go back again
- if ($self->_next_token =~ /^SELECT|INSERT|UPDATE|DELETE$/i) {
- $self->_back;
+ elsif ( $token eq ')' )
+ {
+ if ($self->{ '_is_in_constraint' } and defined $self->_next_token
+ and ($self->_next_token eq ',' or $self->_next_token eq ')')) {
+ $self->{ '_is_in_constraint' } = 0;
}
- if ($self->{ '_is_in_create' } <= 1) {
- my $next_tok = quotemeta($self->_next_token);
- $self->_new_line
- if (defined $self->_next_token
- and $self->_next_token !~ /^AS|THEN|INTO|BETWEEN|ON$/i
- and ($self->_next_token !~ /^AND|OR$/i or !$self->{ '_is_in_if' })
- and $self->_next_token ne ')'
- and $self->_next_token !~ /^:/
- and $self->_next_token ne ';'
- and $self->_next_token ne ','
- and $self->_next_token ne '||'
- and ($self->_is_keyword($self->_next_token) or $self->_is_function($self->_next_token))
- and !exists $self->{ 'dict' }->{ 'symbols' }{ $next_tok }
- );
+ if ($self->{ '_is_in_with' } == 1 || $self->{ '_is_in_explain' }) {
+ $self->_back($token, $last);
+ $self->_new_line($token,$last) if (!$self->{ 'wrap_after' });
+ $self->_add_token( $token );
+ $self->{ '_is_in_explain' } = 0;
+ next;
+ }
+ if ($self->{ 'format_type' } && $self->{ '_current_sql_stmt' } =~ /FUNCTION|PROCEDURE/i
+ && $self->{ '_is_in_create' } == 2
+ ) {
+ $self->_back($token, $last) if ($self->{ '_is_in_block' } < 0);
+ $self->_new_line($token,$last) if (defined $last && $last ne '(');
}
- }
+ if ($self->{ '_is_in_index' } || $self->{ '_is_in_alter' }
+ || $self->{ '_is_in_partition' } || $self->{ '_is_in_policy' }
+ || (defined $self->_next_token and $self->_next_token =~ /^OVER$/i)
+ ) {
+ $self->_add_token( '' );
+ $self->_add_token( $token );
+ $self->{ '_is_in_over' } = 0 if (!$self->{ '_parenthesis_level' });
+ $last = $token;
+ $self->{ '_is_in_create' }-- if ($self->{ '_is_in_create' });
+ next;
+ }
+ if (defined $self->_next_token && $self->_next_token !~ /FILTER/i)
+ {
- elsif ( $token eq ',' ) {
- my $add_newline = 0;
- $add_newline = 1 if ( !$self->{ 'no_break' }
- && !$self->{ '_is_in_function' }
- && ($self->{ 'comma_break' } || $self->{ '_current_sql_stmt' } ne 'INSERT')
- && ($self->{ '_current_sql_stmt' } ne 'RAISE')
- && ($self->{ '_current_sql_stmt' } !~ /^FUNCTION|PROCEDURE$/
+ my $add_nl = 0;
+ $add_nl = 1 if ($self->{ '_is_in_create' } > 1
+ and defined $last and $last ne '('
+ and (not defined $self->_next_token or $self->_next_token =~ /^PARTITION|;$/i or ($self->_next_token =~ /^ON$/i and !$self->{ '_parenthesis_level' }))
+ );
+ $add_nl = 1 if ($self->{ '_is_in_type' } == 1
+ and $self->_next_token !~ /^AS$/i
+ and (not defined $self->_next_token or $self->_next_token eq ';')
+ );
+ $add_nl = 1 if ($self->{ '_current_sql_stmt' } ne 'INSERT'
+ and !$self->{ '_is_in_function' }
+ and (defined $self->_next_token
+ and $self->_next_token =~ /^(SELECT|WITH)$/i)
+ and ($self->{ '_is_in_create' } or $last ne ')' and $last ne ']')
+ );
+ $self->_new_line($token,$last) if ($add_nl);
+ $self->_back($token, $last) if (!$self->{ '_is_in_grouping' }
+ && !$self->{ '_is_in_trigger' } && !$self->{ 'no_break' }
+ );
+ $self->{ '_is_in_create' }-- if ($self->{ '_is_in_create' });
+ $self->{ '_is_in_type' }-- if ($self->{ '_is_in_type' });
+ }
+ if (!$self->{ '_parenthesis_level' }) {
+ $self->{ '_is_in_filter' } = 0;
+ $self->{ '_is_in_within' } = 0;
+ $self->{ '_is_in_grouping' } = 0;
+ $self->{ '_is_in_over' } = 0;
+ $self->{ '_has_order_by' } = 0;
+ $self->{ '_is_in_policy' } = 0;
+ $self->{ '_is_in_where' } = 0;
+ $self->{ '_is_in_aggregate' } = 0;
+ }
+ $self->_add_token( $token );
+ # Do not go further if this is the last token
+ if (not defined $self->_next_token) {
+ $last = $token;
+ next;
+ }
+
+ # When closing CTE statement go back again
+ if ($self->_next_token =~ /^SELECT|INSERT|UPDATE|DELETE$/i && !$self->{ '_is_in_policy' }) {
+ $self->_back($token, $last);
+ }
+ if ($self->{ '_is_in_create' } <= 1) {
+ my $next_tok = quotemeta($self->_next_token);
+ $self->_new_line($token,$last)
+ if (defined $self->_next_token
+ and $self->_next_token !~ /^AS|IS|THEN|INTO|BETWEEN|ON|FILTER|WITHIN$/i
+ and ($self->_next_token !~ /^AND|OR$/i or !$self->{ '_is_in_if' })
+ and $self->_next_token ne ')'
+ and $self->_next_token !~ /^:/
+ and $self->_next_token ne ';'
+ and $self->_next_token ne ','
+ and $self->_next_token ne '||'
+ and ($self->_is_keyword($self->_next_token) or $self->_is_function($self->_next_token))
+ and $self->{ '_current_sql_stmt' } !~ /^(GRANT|REVOKE)$/
+ and !exists $self->{ 'dict' }->{ 'symbols' }{ $next_tok }
+ );
+ }
+ }
+
+ elsif ( $token eq ',' )
+ {
+ my $add_newline = 0;
+ $self->{ '_is_in_constraint' } = 0 if ($self->{ '_is_in_constraint' } == 1);
+ $self->{ '_col_count' }++ if (!$self->{ '_is_in_function' });
+ if (($self->{ '_is_in_over' } or $self->{ '_has_order_by' }) and !$self->{ '_parenthesis_level' } and !$self->{ '_parenthesis_function_level' })
+ {
+ $self->{ '_is_in_over' } = 0;
+ $self->{ '_has_order_by' } = 0;
+ $self->_back($token, $last);
+ }
+ $add_newline = 1 if ( !$self->{ 'no_break' }
+ && !$self->{ '_is_in_function' }
+ && !$self->{ '_is_in_distinct' }
+ && !$self->{ '_is_in_array' }
+ && ($self->{ 'comma_break' } || $self->{ '_current_sql_stmt' } ne 'INSERT')
+ && ($self->{ '_current_sql_stmt' } ne 'RAISE')
+ && ($self->{ '_current_sql_stmt' } !~ /^(FUNCTION|PROCEDURE)$/
|| $self->{ '_fct_code_delimiter' } ne '')
- && !$self->{ '_is_in_where' }
- && !$self->{ '_is_in_index' }
- && $self->{ '_current_sql_stmt' } !~ /^(GRANT|REVOKE)$/
- && $self->_next_token !~ /^('$|\-\-)/i
- && !$self->{ '_parenthesis_function_level' }
- );
-
- if ($self->{ '_is_in_with' } >= 1 && !$self->{ '_parenthesis_level' }) {
- $add_newline = 1;
+ && !$self->{ '_is_in_where' }
+ && !$self->{ '_is_in_drop' }
+ && !$self->{ '_is_in_index' }
+ && !$self->{ '_is_in_aggregate' }
+ && !$self->{ '_is_in_alter' }
+ && !$self->{ '_is_in_publication' }
+ && !$self->{ '_is_in_call' }
+ && !$self->{ '_is_in_policy' }
+ && !$self->{ '_is_in_grouping' }
+ && !$self->{ '_is_in_partition' }
+ && ($self->{ '_is_in_constraint' } <= 1)
+ && $self->{ '_is_in_operator' } != 1
+ && !$self->{ '_has_order_by' }
+ && $self->{ '_current_sql_stmt' } !~ /^(GRANT|REVOKE)$/
+ && $self->_next_token !~ /^('$|\s*\-\-)/i
+ && !$self->{ '_parenthesis_function_level' }
+ && (!$self->{ '_col_count' } or $self->{ '_col_count' } > ($self->{ 'wrap_after' } - 1))
+ || ($self->{ '_is_in_with' } and !$self->{ 'wrap_after' })
+ );
+ $self->{ '_col_count' } = 0 if ($self->{ '_col_count' } > ($self->{ 'wrap_after' } - 1));
+ $add_newline = 0 if ($self->{ '_is_in_using' } and $self->{ '_parenthesis_level' });
+ $add_newline = 0 if ($self->{ 'no_break' });
+
+ if ($self->{ '_is_in_with' } >= 1 && !$self->{ '_parenthesis_level' }) {
+ $add_newline = 1 if (!$self->{ 'wrap_after' });
+ }
+ if ($self->{ 'format_type' } && $self->{ '_current_sql_stmt' } =~ /FUNCTION|PROCEDURE/i && $self->{ '_is_in_create' } == 2) {
+ $add_newline = 1;
}
- $self->_new_line if ($add_newline && $self->{ 'comma' } eq 'start');
- $self->_add_token( $token );
- $self->_new_line if ($add_newline && $self->{ 'comma' } eq 'end');
- }
+ if ($self->{ '_is_in_alter' } && $self->{ '_is_in_operator' } >= 2) {
+ $add_newline = 1 if (defined $self->_next_token and $self->_next_token =~ /^OPERATOR|FUNCTION$/i);
+ }
+ $self->_new_line($token,$last) if ($add_newline && $self->{ 'comma' } eq 'start');
+ $self->_add_token( $token );
+ $add_newline = 0 if ($self->{ '_is_in_value' } and $self->{ '_parenthesis_level_value' });
+ $self->_new_line($token,$last) if ($add_newline && $self->{ 'comma' } eq 'end');
+ }
- elsif ( $token eq ';' or $token =~ /^\\(?:g|crosstabview|watch)/ ) { # statement separator or executing psql meta command (prefix 'g' includes all its variants)
- # Initialize most of statement related variables
- $self->{ '_has_from' } = 0;
- $self->{ '_is_in_where' } = 0;
- $self->{ '_is_in_from' } = 0;
- $self->{ '_is_in_join' } = 0;
- $self->{ '_is_in_create' } = 0;
- $self->{ '_is_in_type' } = 0;
- $self->{ '_is_in_function' } = 0;
- $self->{ '_is_in_index' } = 0;
- $self->{ '_is_in_if' } = 0;
- $self->{ '_current_sql_stmt' } = '';
- $self->{ '_is_in_with' } = 0;
- $self->{ '_has_order_by' } = 0;
- $self->{ '_has_over_in_join' } = 0;
- $self->{ '_parenthesis_level' } = 0;
- $self->{ '_parenthesis_function_level' } = 0;
- $self->_add_token($token);
- $self->{ 'break' } = "\n" unless ( $self->{ 'spaces' } != 0 );
- $self->_new_line;
- # Add an additional newline after ; when we are not in a function
- if ($self->{ '_is_in_block' } == -1 and !$self->{ '_is_in_declare' } and !$self->{ '_fct_code_delimiter' })
- {
- $self->{ '_new_line' } = 0;
- $self->_new_line;
+ elsif ( $token eq ';' or $token =~ /^\\(?:g|crosstabview|watch)/ ) { # statement separator or executing psql meta command (prefix 'g' includes all its variants)
+
+ $self->_add_token($token);
+
+ if ($self->{ '_is_in_rule' }) {
+ $self->_back($token, $last);
}
- # End of statement; remove all indentation when we are not in a BEGIN/END block
- if (!$self->{ '_is_in_declare' } && $self->{ '_is_in_block' } == -1)
+ elsif ($self->{ '_is_in_create' } && $self->{ '_is_in_block' } > -1)
{
- @{ $self->{ '_level_stack' } } = ();
- $self->{ '_level' } = 0;
- $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
+ $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0;
}
- else
+
+ # Initialize most of statement related variables
+ $self->{ 'no_break' } = 0;
+ $self->{ '_is_in_where' } = 0;
+ $self->{ '_is_in_from' } = 0;
+ $self->{ '_is_in_join' } = 0;
+ $self->{ '_is_in_create' } = 0;
+ $self->{ '_is_in_alter' } = 0;
+ $self->{ '_is_in_rule' } = 0;
+ $self->{ '_is_in_publication' } = 0;
+ $self->{ '_is_in_call' } = 0;
+ $self->{ '_is_in_type' } = 0;
+ $self->{ '_is_in_function' } = 0;
+ $self->{ '_is_in_prodedure' } = 0;
+ $self->{ '_is_in_index' } = 0;
+ $self->{ '_is_in_if' } = 0;
+ $self->{ '_is_in_with' } = 0;
+ $self->{ '_has_order_by' } = 0;
+ $self->{ '_has_over_in_join' } = 0;
+ $self->{ '_parenthesis_level' } = 0;
+ $self->{ '_parenthesis_function_level' } = 0;
+ $self->{ '_is_in_constraint' } = 0;
+ $self->{ '_is_in_distinct' } = 0;
+ $self->{ '_is_in_array' } = 0;
+ $self->{ '_is_in_filter' } = 0;
+ $self->{ '_parenthesis_filter_level' } = 0;
+ $self->{ '_is_in_partition' } = 0;
+ $self->{ '_is_in_over' } = 0;
+ $self->{ '_is_in_policy' } = 0;
+ $self->{ '_is_in_trigger' } = 0;
+ $self->{ '_is_in_using' } = 0;
+ $self->{ '_and_level' } = 0;
+ $self->{ '_col_count' } = 0;
+ $self->{ '_is_in_drop' } = 0;
+ $self->{ '_is_in_conversion' } = 0;
+ $self->{ '_is_in_operator' } = 0;
+ $self->{ '_is_in_explain' } = 0;
+ $self->{ '_is_in_sub_query' } = 0;
+ $self->{ '_is_in_fetch' } = 0;
+ $self->{ '_is_in_aggregate' } = 0;
+ $self->{ '_is_in_value' } = 0;
+ $self->{ '_parenthesis_level_value' } = 0;
+
+ if ( $self->{ '_insert_values' } )
{
- if ($#{ $self->{ '_level_stack' } } == -1) {
- $self->{ '_level' } = ($self->{ '_is_in_declare' }) ? 1 : ($self->{ '_is_in_block' }+1);
- } else {
- $self->{ '_level' } = $self->{ '_level_stack' }[-1];
+ if ($self->{ '_is_in_block' } == -1 and !$self->{ '_is_in_declare' } and !$self->{ '_fct_code_delimiter' })
+ {
+ @{ $self->{ '_level_stack' } } = ();
+ $self->{ '_level' } = 0;
+ $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
}
+ elsif ($self->{ '_is_in_block' } == -1 and $self->{ '_current_sql_stmt' } eq 'INSERT' and !$self->{ '_is_in_create' } and !$self->{ '_is_in_create_function' })
+ {
+ $self->_back($token, $last);
+ pop( @{ $self->{ '_level_stack' } } );
+ }
+ else
+ {
+ $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0;
+ }
+ $self->{ '_insert_values' } = 0;
}
- }
- elsif ($token =~ /^FOR$/i)
+ $self->{ '_current_sql_stmt' } = '';
+ $self->{ 'break' } = "\n" unless ( $self->{ 'spaces' } != 0 );
+ $self->_new_line($token,$last);
+ # Add an additional newline after ; when we are not in a function
+ if ($self->{ '_is_in_block' } == -1 and !$self->{ '_is_in_work' }
+ and !$self->{ '_is_in_declare' })
+ #and !$self->{ '_is_in_declare' } and !$self->{ '_fct_code_delimiter' })
+ {
+ $self->{ '_new_line' } = 0;
+ $self->_new_line($token,$last);
+ }
+ # End of statement; remove all indentation when we are not in a BEGIN/END block
+ if (!$self->{ '_is_in_declare' } && $self->{ '_is_in_block' } == -1)
+ {
+ @{ $self->{ '_level_stack' } } = ();
+ $self->{ '_level' } = 0;
+ $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
+ }
+ elsif (not defined $self->_next_token or $self->_next_token !~ /^INSERT$/)
+ {
+ if ($#{ $self->{ '_level_stack' } } == -1) {
+ $self->{ '_level' } = ($self->{ '_is_in_declare' }) ? 1 : ($self->{ '_is_in_block' }+1);
+ } else {
+ $self->{ '_level' } = $self->{ '_level_stack' }[-1];
+ }
+ }
+ $last = $token;
+ }
+ elsif ($token =~ /^FOR$/i && (!$self->{ '_is_in_policy' } || $self->{ 'format_type' }))
{
- if ($self->_next_token =~ /^(UPDATE|KEY|NO)$/i)
+ if ($self->_next_token =~ /^(UPDATE|KEY|NO|VALUES)$/i)
{
- $self->_back;
- $self->_new_line;
+ $self->_back($token, $last);
+ $self->_new_line($token,$last);
+ }
+ elsif ($self->_next_token =~ /^EACH$/ and $self->{ '_is_in_trigger' })
+ {
+ $self->_new_line($token,$last);
}
- $self->_add_token( $token );
- if ($self->_next_token =~ /^SELECT$/i)
+ if (!$self->{ 'format_type' })
{
- $self->_new_line;
- $self->_over;
+ $self->_add_token( $token );
+ # cover FOR in cursor
+ $self->_over($token,$last) if (uc($self->_next_token) eq 'SELECT' && !$self->{ '_is_in_policy' } && !$self->{ '_is_in_publication' });
+ $last = $token;
+ next;
}
- }
+ if ($self->_next_token =~ /^SELECT|UPDATE|DELETE|INSERT|TABLE|ALL$/i)
+ {
+ # cover FOR in cursor and in policy or publication statements
+ $self->_over($token,$last) if (uc($self->_next_token) eq 'SELECT' || $self->{ '_is_in_policy' } || $self->{ '_is_in_publication' });
+ }
+ if ($self->{ 'format_type' } && $self->{ '_is_in_policy' } || $self->{ '_is_in_publication' }) {
+ $self->_new_line($token,$last);
+ }
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
- elsif ( $token =~ /^(?:FROM|WHERE|SET|RETURNING|HAVING|VALUES)$/i )
+ elsif ( $token =~ /^(?:FROM|WHERE|SET|RETURNING|HAVING|VALUES)$/i )
{
+ if (uc($token) eq 'FROM' and $self->{ '_has_order_by' } and !$self->{ '_parenthesis_level' })
+ {
+ $self->_back($token, $last) if ($self->{ '_has_order_by' });
+ }
$self->{ 'no_break' } = 0;
-
- if (uc($last) eq 'DISTINCT' and $token =~ /^FROM$/i)
+ $self->{ '_col_count' } = 0;
+ # special cases for create partition statement
+ if ($token =~ /^VALUES$/i && defined $last and $last =~ /^FOR|IN$/i)
{
$self->_add_token( $token );
+ $self->{ 'no_break' } = 1;
$last = $token;
next;
}
- if (($token =~ /^FROM$/i) && $self->{ '_has_from' } && !$self->{ '_is_in_function' })
+ elsif ($token =~ /^FROM$/i && defined $last and uc($last) eq 'VALUES')
{
- $self->{ '_has_from' } = 0;
+ $self->_add_token( $token );
+ $last = $token;
+ next;
}
- if ($token =~ /^FROM$/i)
+
+ # Case of DISTINCT FROM clause
+ if ($token =~ /^FROM$/i)
{
- $self->{ '_is_in_from' }++ if (!$self->{ '_is_in_function' });
+ if (uc($last) eq 'DISTINCT' || $self->{ '_is_in_fetch' } || $self->{ '_is_in_alter' } || $self->{ '_is_in_conversion' })
+ {
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
}
- if ($token =~ /^WHERE$/i)
+
+ if ($token =~ /^FROM$/i)
{
- $self->_back() if ($self->{ '_has_over_in_join' });
- $self->{ '_is_in_where' }++;
- $self->{ '_is_in_from' }-- if ($self->{ '_is_in_from' });
- $self->{ '_is_in_join' } = 0;
- $self->{ '_has_over_in_join' } = 0;
- }
+ $self->{ '_is_in_from' }++ if (!$self->{ '_is_in_function' } && !$self->{ '_is_in_partition' });
+ }
+
+ if ($token =~ /^WHERE$/i && !$self->{ '_is_in_filter' })
+ {
+ $self->_back($token, $last) if ($self->{ '_has_over_in_join' });
+ $self->{ '_is_in_where' }++;
+ $self->{ '_is_in_from' }-- if ($self->{ '_is_in_from' });
+ $self->{ '_is_in_join' } = 0;
+ $self->{ '_has_over_in_join' } = 0;
+ }
elsif (!$self->{ '_is_in_function' })
{
- $self->{ '_is_in_where' }-- if ($self->{ '_is_in_where' });
- }
+ $self->{ '_is_in_where' }-- if ($self->{ '_is_in_where' });
+ }
- if ($token =~ /^SET$/i and $self->{ '_is_in_create' })
+ if ($token =~ /^SET$/i and $self->{ '_is_in_create' })
{
- # Add newline before SET statement in function header
- $self->_new_line;
- }
+ # Add newline before SET statement in function header
+ $self->_new_line($token,$last) if (not defined $last or $last !~ /DELETE|UPDATE/i);
+ }
elsif ($token =~ /^WHERE$/i and $self->{ '_current_sql_stmt' } eq 'DELETE')
{
- $self->_new_line;
- $self->_add_token( $token );
- $self->_over;
- $last = $token;
- $self->{ '_is_in_join' } = 0;
- next;
- }
+ $self->_new_line($token,$last);
+ $self->_add_token( $token );
+ $self->_over($token,$last);
+ $last = $token;
+ $self->{ '_is_in_join' } = 0;
+ $last = $token;
+ next;
+ }
elsif ($token !~ /^FROM$/i or (!$self->{ '_is_in_function' }
- and $self->{ '_current_sql_stmt' } ne 'DELETE'))
+ and $self->{ '_current_sql_stmt' } !~ /DELETE|REVOKE/))
{
- if ($token !~ /^SET$/i or !$self->{ '_is_in_index' })
+ if (!$self->{ '_is_in_filter' } and ($token !~ /^SET$/i or !$self->{ '_is_in_index' }))
{
- $self->_back;
- $self->_new_line;
- }
- }
+ $self->_back($token, $last);
+ $self->_new_line($token,$last) if (!$self->{ '_is_in_rule' });
+ }
+ }
else
{
- $self->_add_token( $token );
- $last = $token;
- next;
- }
- if ($token =~ /^VALUES$/i and ($self->{ '_current_sql_stmt' } eq 'INSERT' or $last eq '('))
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
+
+ if ($token =~ /^VALUES$/i and !$self->{ '_is_in_rule' } and ($self->{ '_current_sql_stmt' } eq 'INSERT' or $last eq '('))
{
- $self->_over;
+ $self->_over($token,$last);
+ if ($self->{ '_current_sql_stmt' } eq 'INSERT' or $last eq '(') {
+ $self->{ '_insert_values' } = 1;
+ push @{ $self->{ '_level_stack' } }, $self->{ '_level' };
+ }
}
- $self->_add_token( $token );
+
if ($token =~ /^VALUES$/i and $last eq '(')
+ {
+ $self->{ '_is_in_value' } = 1;
+ }
+
+ if (uc($token) eq 'WHERE')
{
- $self->_over;
- }
- elsif ( $token =~ /^SET$/i && $self->{ '_current_sql_stmt' } eq 'UPDATE' )
+ $self->_add_token( $token, $last );
+ $self->{ '_is_in_value' } = 0;
+ $self->{ '_parenthesis_level_value' } = 0;
+ }
+ else
{
- $self->_new_line;
- $self->_over;
- }
- elsif ( $token !~ /^SET$/i || $self->{ '_current_sql_stmt' } eq 'UPDATE' )
+ $self->_add_token( $token );
+ }
+
+ if ($token =~ /^VALUES$/i and $last eq '(')
{
- if (defined $self->_next_token and $self->_next_token ne '('
+ $self->_over($token,$last);
+ }
+ elsif ( $token =~ /^SET$/i && $self->{ '_current_sql_stmt' } eq 'UPDATE' )
+ {
+ $self->_new_line($token,$last) if (!$self->{ 'wrap_after' });
+ $self->_over($token,$last);
+ }
+ elsif ( !$self->{ '_is_in_over' } and !$self->{ '_is_in_filter' } and ($token !~ /^SET$/i or $self->{ '_current_sql_stmt' } eq 'UPDATE') )
+ {
+ if (defined $self->_next_token and $self->_next_token ne '('
and ($self->_next_token !~ /^(UPDATE|KEY|NO)$/i || uc($token) eq 'WHERE'))
{
- $self->_new_line;
- $self->_over;
- }
- }
- }
-
- # Add newline before INSERT and DELETE if last token was AS (prepared statement)
- elsif (defined $last and $token =~ /^INSERT|DELETE$/i and uc($last) eq 'AS')
+ $self->_new_line($token,$last) if (!$self->{ 'wrap_after' });
+ $self->_over($token,$last);
+ }
+ }
+ }
+
+ # Add newline before INSERT and DELETE if last token was AS (prepared statement)
+ elsif (defined $last and $token =~ /^INSERT|DELETE$/i and uc($last) eq 'AS')
{
- $self->_new_line;
- $self->_add_token( $token );
- }
-
- elsif ( $self->{ '_current_sql_stmt' } !~ /^(GRANT|REVOKE)$/
- and $token =~ /^(?:SELECT|PERFORM|UPDATE|DELETE)$/i )
+ $self->_new_line($token,$last);
+ $self->_add_token( $token );
+ }
+
+ elsif ( $self->{ '_current_sql_stmt' } !~ /^(GRANT|REVOKE)$/
+ and $token =~ /^(?:SELECT|PERFORM|UPDATE|DELETE)$/i
+ and (!$self->{ '_is_in_policy' } || $self->{ 'format_type' })
+ )
{
- $self->{ 'no_break' } = 0;
+ $self->{ 'no_break' } = 0;
- if ($token =~ /^UPDATE$/i and $last =~ /^(FOR|KEY)$/i)
+ if ($token =~ /^SELECT|UPDATE|DELETE|INSERT$/i && $self->{ '_is_in_policy' } && $self->{ 'format_type' })
{
- $self->_add_token( $token );
+ $self->_over($token,$last);
}
- elsif ($token !~ /^DELETE$/i)
+
+ # case of ON DELETE/UPDATE clause in create table statements
+ if ($token =~ /^UPDATE|DELETE$/i && $self->{ '_is_in_create' }) {
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
+ if ($token =~ /^UPDATE$/i and $last =~ /^(FOR|KEY)$/i)
{
- $self->_new_line;
- $self->_add_token( $token );
- $self->_new_line;
- $self->_over;
- }
+ $self->_add_token( $token );
+ }
+ elsif (!$self->{ '_is_in_policy' } && $token !~ /^DELETE$/i && (!defined $self->_next_token || $self->_next_token !~ /^DISTINCT$/i))
+ {
+ $self->_new_line($token,$last);
+ $self->_add_token( $token );
+ $self->_new_line($token,$last) if (!$self->{ 'wrap_after' });
+ $self->_over($token,$last);
+ }
else
{
- $self->_add_token( $token );
- }
- }
+ $self->_add_token( $token );
+ }
+ }
- elsif ( $token =~ /^(?:GROUP|ORDER|LIMIT|EXCEPTION)$/i )
+ elsif ( $self->{ '_current_sql_stmt' } !~ /^(GRANT|REVOKE)$/
+ and uc($token) eq 'INSERT'
+ and $self->{ '_is_in_policy' } && $self->{ 'format_type' })
{
- $self->{ '_is_in_join' } = 0;
- if ($token !~ /^EXCEPTION$/i) {
- $self->_back;
- } else {
- $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0;
- }
- $self->_new_line;
- $self->_add_token( $token );
- # Store current indent position to print END at the right level
- if ($token =~ /^EXCEPTION$/i)
- {
- push @{ $self->{ '_level_stack' } }, $self->{ '_level' };
- $self->_over;
- }
- $self->{ '_is_in_where' }-- if ($self->{ '_is_in_where' });
+ $self->_add_token( $token );
+ $self->_new_line($token,$last);
+ $self->_over($token,$last);
}
-
- elsif ( $token =~ /^(?:BY)$/i and $last !~ /^(INCREMENT|OWNED)$/ )
+ elsif ( $token =~ /^(?:WITHIN)$/i )
{
- $self->_add_token( $token );
- $self->_new_line;
- $self->_over;
+ $self->{ '_is_in_within' } = 1;
+ $self->{ '_has_order_by' } = 1;
+ $self->_add_token( $token );
+ $last = $token;
+ next;
}
- elsif ( $token =~ /^(?:CASE)$/i )
+ elsif ( $token =~ /^(?:GROUP|ORDER|LIMIT|EXCEPTION)$/i )
{
- $self->_add_token( $token );
- # Store current indent position to print END at the right level
- push @{ $self->{ '_level_stack' } }, $self->{ '_level' };
- # Mark next WHEN statement as first element of a case
- # to force indentation only after this element
- $self->{ '_first_when_in_case' } = 1;
- $self->{ '_is_in_case' }++;
- }
-
- elsif ( $token =~ /^(?:WHEN)$/i )
+ $self->{ '_is_in_value' } = 0;
+ $self->{ '_parenthesis_level_value' } = 0;
+ if (uc($token) eq 'GROUP' and !defined $last or uc($last) eq 'EXCLUDE') {
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
+ if (($self->{ '_is_in_within' } && uc($token) eq 'GROUP') || ($self->{ '_is_in_over' } && uc($token) eq 'ORDER')) {
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
+ if ($self->{ '_has_over_in_join' } and uc($token) eq 'GROUP')
+ {
+ $self->_back($token, $last);
+ $self->{ '_has_over_in_join' } = 0;
+ }
+ $self->{ '_is_in_join' } = 0;
+ if ($token !~ /^EXCEPTION$/i) {
+ $self->_back($token, $last);
+ } else {
+ $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0;
+ }
+ if (uc($token) ne 'EXCEPTION' or not defined $last or uc($last) ne 'RAISE')
+ {
+ # Excluding CREATE/DROP GROUP
+ $self->_new_line($token,$last) if (not defined $last or $last !~ /^(CREATE|DROP)$/);
+ }
+ $self->_add_token( $token );
+ # Store current indent position to print END at the right level
+ if ($token =~ /^EXCEPTION$/i)
+ {
+ push @{ $self->{ '_level_stack' } }, $self->{ '_level' };
+ $self->_over($token,$last);
+ $self->{ '_is_in_exception' } = 1;
+ }
+ $self->{ '_is_in_where' }-- if ($self->{ '_is_in_where' });
+ }
+
+ elsif ( $token =~ /^(?:BY)$/i and $last !~ /^(?:INCREMENT|OWNED|PARTITION)$/i)
{
- $self->_back if (!$self->{ '_first_when_in_case' } and defined $last and uc($last) ne 'CASE');
- $self->_new_line if (not defined $last or uc($last) ne 'CASE');
- $self->_add_token( $token );
- $self->_over;
- $self->{ '_first_when_in_case' } = 0;
- }
+ $self->_add_token( $token );
+ $self->{ '_col_count' } = 0 if (defined $last && $last =~ /^(?:GROUP|ORDER)/i);
+ if (!$self->{ '_has_order_by' }) {
+ $self->_new_line($token,$last) if (!$self->{ 'wrap_after' });
+ $self->_over($token,$last);
+ }
+ }
- elsif ( $token =~ /^(?:IF|LOOP)$/i )
+ elsif ( $token =~ /^(?:CASE)$/i )
{
- $self->_add_token( $token );
- if (defined $self->_next_token and $self->_next_token ne ';')
+ $self->_add_token( $token );
+ # Store current indent position to print END at the right level
+ push @{ $self->{ '_level_stack' } }, $self->{ '_level' };
+ # Mark next WHEN statement as first element of a case
+ # to force indentation only after this element
+ $self->{ '_first_when_in_case' } = 1;
+ $self->{ '_is_in_case' }++;
+ }
+
+ elsif ( $token =~ /^(?:WHEN)$/i)
+ {
+ if (!$self->{ '_first_when_in_case' } and !$self->{'_is_in_trigger'}
+ and defined $last and uc($last) ne 'CASE'
+ # handle case where there is a comment between EXCEPTION and WHEN keywords
+ and !$self->{ '_is_in_exception' }
+ )
{
- $self->_new_line if ($token =~ /^LOOP$/i);
- $self->_over;
- push @{ $self->{ '_level_stack' } }, $self->{ '_level' };
- if ($token =~ /^IF$/i) {
- $self->{ '_is_in_if' } = 1;
- }
+ $self->{ '_level' } = $self->{ '_level_stack' }[-1];
+ $self->{ '_is_in_exception' } = 0;
}
- }
+ $self->_new_line($token,$last) if (not defined $last or uc($last) ne 'CASE');
+ $self->_add_token( $token );
+ if (!$self->{ '_is_in_case' } && !$self->{ '_is_in_trigger' }) {
+ $self->_over($token,$last);
+ }
+ $self->{ '_first_when_in_case' } = 0;
+ }
- elsif ($token =~ /^THEN$/i)
+ elsif ( $token =~ /^(?:IF|LOOP)$/i && $self->{ '_current_sql_stmt' } ne 'GRANT')
{
- $self->_add_token( $token );
- $self->_new_line;
- $self->{ '_is_in_if' } = 0;
- }
-
- elsif ( $token =~ /^(?:ELSE|ELSIF)$/i )
+ $self->_add_token( $token );
+ $self->{ 'no_break' } = 0;
+ if (defined $self->_next_token and $self->_next_token !~ /^(EXISTS|;)$/i)
+ {
+ $self->_new_line($token,$last) if ($token =~ /^LOOP$/i);
+ $self->_over($token,$last);
+ push @{ $self->{ '_level_stack' } }, $self->{ '_level' };
+ if ($token =~ /^IF$/i) {
+ $self->{ '_is_in_if' } = 1;
+ }
+ }
+ }
+
+ elsif ($token =~ /^THEN$/i)
{
- $self->_back;
- $self->_new_line;
- $self->_add_token( $token );
- $self->_new_line if ($token !~ /^ELSIF$/i);
- $self->_over;
- }
+ $self->_add_token( $token );
+ $self->_new_line($token,$last);
+ $self->{ '_level' } = $self->{ '_level_stack' }[-1] if ($self->{ '_is_in_if' });
+ if ($self->{ '_is_in_case' } && defined $self->_next_token() and $self->_next_token() !~ /^(\(|RAISE)$/i) {
+ $self->{ '_level' } = $self->{ '_level_stack' }[-1];
+ $self->_over($token,$last);
+ }
+ $self->{ '_is_in_if' } = 0;
+ }
- elsif ( $token =~ /^(?:END)$/i )
+ elsif ( $token =~ /^(?:ELSE|ELSIF)$/i )
+ {
+ $self->_back($token, $last);
+ $self->_new_line($token,$last);
+ $self->_add_token( $token );
+ $self->_new_line($token,$last) if ($token !~ /^ELSIF$/i);
+ $self->_over($token,$last);
+ }
+
+ elsif ( $token =~ /^(?:END)$/i )
{
- $self->{ '_first_when_in_case' } = 0;
- if ($self->{ '_is_in_case' })
+ $self->{ '_first_when_in_case' } = 0;
+ if ($self->{ '_is_in_case' })
{
- $self->{ '_is_in_case' }--;
- $self->_back;
- }
- # When we are not in a function code block (0 is the main begin/end block of a function)
- elsif ($self->{ '_is_in_block' } == -1)
+ $self->{ '_is_in_case' }--;
+ $self->_back($token, $last);
+ $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0;
+ }
+ # When we are not in a function code block (0 is the main begin/end block of a function)
+ elsif ($self->{ '_is_in_block' } == -1)
{
- # END is closing a create function statement so reset position to begining
- if ($self->_next_token !~ /^(IF|LOOP|CASE|INTO|FROM|END|ELSE|AND|OR|WHEN|AS|,)$/i)
+ # END is closing a create function statement so reset position to begining
+ if ($self->_next_token !~ /^(IF|LOOP|CASE|INTO|FROM|END|ELSE|AND|OR|WHEN|AS|,)$/i)
{
- @{ $self->{ '_level_stack' } } = ();
- $self->{ '_level' } = 0;
- $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
- }
+ @{ $self->{ '_level_stack' } } = ();
+ $self->{ '_level' } = 0;
+ $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
+ }
else
{
- # otherwise back to last level stored at CASE keyword
- $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0;
- }
- # We are in code block
+ # otherwise back to last level stored at CASE keyword
+ $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0;
+ }
}
+ # We reach the last end of the code
+ elsif ($self->{ '_is_in_block' } > -1 and $self->_next_token eq ';' and !$self->{ '_is_in_exception' })
+ {
+ @{ $self->{ '_level_stack' } } = ();
+ $self->{ '_level' } = 0;
+ $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
+ }
+ # We are in code block
else
{
- # decrease the block level if this is a END closing a BEGIN block
- if ($self->_next_token !~ /^(IF|LOOP|CASE|INTO|FROM|END|ELSE|AND|OR|WHEN|AS|,)$/i)
+ # decrease the block level if this is a END closing a BEGIN block
+ if ($self->_next_token !~ /^(IF|LOOP|CASE|INTO|FROM|END|ELSE|AND|OR|WHEN|AS|,)$/i)
{
- $self->{ '_is_in_block' }--;
- }
- # Go back to level stored with IF/LOOP/BEGIN/EXCEPTION block
- $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0;
- $self->_back if ($self->_next_token =~ /^(IF|LOOP|CASE|INTO|FROM|END|ELSE|AND|OR|WHEN|AS|,)$/i);
- }
- $self->_new_line;
- $self->_add_token( $token );
- }
-
- elsif ( $token =~ /^(?:UNION|INTERSECT|EXCEPT)$/i )
+ $self->{ '_is_in_block' }--;
+ }
+ # Go back to level stored with IF/LOOP/BEGIN/EXCEPTION block
+ $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0;
+ $self->_back($token, $last) if ($self->_next_token =~ /^(IF|LOOP|CASE|INTO|FROM|END|ELSE|AND|OR|WHEN|AS|,)$/i);
+ }
+ $self->_new_line($token,$last);
+ $self->_add_token( $token );
+ }
+
+ elsif ( $token =~ /^(?:UNION|INTERSECT|EXCEPT)$/i )
{
- $self->{ 'no_break' } = 0;
- if ($self->{ '_is_in_join' })
+ $self->{ 'no_break' } = 0;
+ if ($self->{ '_is_in_join' })
{
- $self->_back;
- $self->{ '_is_in_join' } = 0;
- }
- $self->_back unless defined $last and $last eq '(';
- $self->_new_line;
- $self->_add_token( $token );
- $self->_new_line if ( defined $self->_next_token
+ $self->_back($token, $last);
+ $self->{ '_is_in_join' } = 0;
+ }
+ $self->_back($token, $last) unless defined $last and $last eq '(';
+ $self->_new_line($token,$last);
+ $self->_add_token( $token );
+ $self->_new_line($token,$last) if ( defined $self->_next_token
and $self->_next_token ne '('
and $self->_next_token !~ /^ALL$/i
);
- $self->{ '_is_in_where' }-- if ($self->{ '_is_in_where' });
- $self->{ '_is_in_from' } = 0;
- }
+ $self->{ '_is_in_where' }-- if ($self->{ '_is_in_where' });
+ $self->{ '_is_in_from' } = 0;
+ }
- elsif ( $token =~ /^(?:LEFT|RIGHT|FULL|INNER|OUTER|CROSS|NATURAL)$/i )
+ elsif ( $token =~ /^(?:LEFT|RIGHT|FULL|INNER|OUTER|CROSS|NATURAL)$/i and (not defined $last or uc($last) ne 'MATCH') )
{
- $self->{ 'no_break' } = 0;
- if (!$self->{ '_is_in_join' } and ($last and $last ne ')') )
+ $self->{ 'no_break' } = 0;
+ if (!$self->{ '_is_in_join' } and ($last and $last ne ')') )
{
- $self->_back;
- }
- if ($self->{ '_has_over_in_join' })
+ $self->_back($token, $last);
+ }
+ if ($self->{ '_has_over_in_join' })
{
- $self->{ '_has_over_in_join' } = 0;
- $self->_back;
- }
+ $self->{ '_has_over_in_join' } = 0;
+ $self->_back($token, $last);
+ }
- if ( $token =~ /(?:LEFT|RIGHT|FULL|CROSS|NATURAL)$/i )
+ if ( $token =~ /(?:LEFT|RIGHT|FULL|CROSS|NATURAL)$/i )
{
- $self->_new_line;
- $self->_over if ( $self->{ '_level' } == 0 );
- }
- if ( ($token =~ /(?:INNER|OUTER)$/i) && ($last !~ /(?:LEFT|RIGHT|CROSS|NATURAL|FULL)$/i) )
+ $self->_new_line($token,$last);
+ $self->_over($token,$last) if ( $self->{ '_level' } == 0 );
+ }
+ if ( ($token =~ /(?:INNER|OUTER)$/i) && ($last !~ /(?:LEFT|RIGHT|CROSS|NATURAL|FULL)$/i) )
{
- $self->_new_line;
- $self->_over if (!$self->{ '_is_in_join' });
- }
- $self->_add_token( $token );
- }
+ $self->_new_line($token,$last);
+ $self->_over($token,$last) if (!$self->{ '_is_in_join' });
+ }
+ $self->_add_token( $token );
+ }
- elsif ( $token =~ /^(?:JOIN)$/i )
+ elsif ( $token =~ /^(?:JOIN)$/i and !$self->{ '_is_in_operator' })
{
- $self->{ 'no_break' } = 0;
- if ( not defined $last or $last !~ /^(?:LEFT|RIGHT|FULL|INNER|OUTER|CROSS|NATURAL)$/i )
+ $self->{ 'no_break' } = 0;
+ if ( not defined $last or $last !~ /^(?:LEFT|RIGHT|FULL|INNER|OUTER|CROSS|NATURAL)$/i )
{
- $self->_new_line;
- $self->_back if ($self->{ '_has_over_in_join' });
- $self->{ '_has_over_in_join' } = 0;
- }
- $self->_add_token( $token );
- $self->{ '_is_in_join' } = 1;
- }
-
- elsif ( $token =~ /^(?:AND|OR)$/i )
+ $self->_new_line($token,$last);
+ $self->_back($token, $last) if ($self->{ '_has_over_in_join' });
+ $self->{ '_has_over_in_join' } = 0;
+ }
+ $self->_add_token( $token );
+ $self->{ '_is_in_join' } = 1;
+ }
+
+ elsif ( $token =~ /^(?:AND|OR)$/i )
{
- # Try to detect AND in BETWEEN clause to prevent newline insert
- if (uc($token) eq 'AND' and $self->_next_token() =~ /^\d+$/)
+ # Try to detect AND in BETWEEN clause to prevent newline insert
+ if (uc($token) eq 'AND' and ($self->_next_token() =~ /^\d+$/ || (defined $last && $last =~ /^(PRECEDING|FOLLOWING|ROW)$/i)))
{
- $self->_add_token( $token );
- next;
- }
- $self->{ 'no_break' } = 0;
- if ($self->{ '_is_in_join' })
+ $self->_add_token( $token );
+ $last = $token;
+ next;
+ }
+ $self->{ 'no_break' } = 0;
+ if ($self->{ '_is_in_join' })
{
- $self->_over;
- $self->{ '_has_over_in_join' } = 1;
- }
- $self->{ '_is_in_join' } = 0;
- if ( !$self->{ '_is_in_if' } and !$self->{ '_is_in_index' }
+ $self->_over($token,$last);
+ $self->{ '_has_over_in_join' } = 1;
+ }
+ $self->{ '_is_in_join' } = 0;
+ if ( !$self->{ '_is_in_if' } and !$self->{ '_is_in_index' }
and (!$last or $last !~ /^(?:CREATE)$/i) )
{
- $self->_new_line;
- }
- $self->_add_token( $token );
- }
-
- elsif ( $token =~ /^--/ )
+ $self->_new_line($token,$last);
+ if (!$self->{'_and_level'} and (!$self->{ '_level' } || $self->{ '_is_in_alter' })) {
+ $self->_over($token,$last);
+ } elsif ($self->{'_and_level'} and !$self->{ '_level' } and uc($token) eq 'OR') {
+ $self->_over($token,$last);
+ } elsif ($#{$self->{ '_level_stack' }} >= 0 and $self->{ '_level' } == $self->{ '_level_stack' }[-1]) {
+ $self->_over($token,$last);
+ }
+ }
+ $self->_add_token( $token );
+ $self->{'_and_level'}++;
+ }
+
+ elsif ( $token =~ /^\/\*.*\*\/$/s )
{
- if ( !$self->{ 'no_comments' } )
+ if ( !$self->{ 'no_comments' } )
{
- $self->_add_token( $token );
- $self->{ 'break' } = "\n" unless ( $self->{ 'spaces' } != 0 );
- $self->_new_line;
- $self->{ 'break' } = ' ' unless ( $self->{ 'spaces' } != 0 );
- }
- else
- {
- $self->_new_line;
- }
- }
-
- elsif ( $token =~ /^\/\*.*\*\/$/s )
- {
- if ( !$self->{ 'no_comments' } )
- {
- $token =~ s/\n[\s\t]+\*/\n\*/gs;
- $self->_new_line;
- $self->_add_token( $token );
- $self->{ 'break' } = "\n" unless ( $self->{ 'spaces' } != 0 );
- $self->_new_line;
- $self->{ 'break' } = " " unless ( $self->{ 'spaces' } != 0 );
- }
- }
-
- elsif ($token =~ /^USING$/i)
+ $token =~ s/\n[\s\t]+\*/\n\*/gs;
+ $self->_new_line($token,$last), $self->_add_token('') if (defined $last and $last eq ';');
+ $self->_new_line($token,$last);
+ $self->_add_token( $token );
+ $self->{ 'break' } = "\n" unless ( $self->{ 'spaces' } != 0 );
+ $self->_new_line($token,$last);
+ $self->{ 'break' } = " " unless ( $self->{ 'spaces' } != 0 );
+ }
+ }
+
+ elsif ($token =~ /^USING$/i and (!$self->{ '_is_in_policy' } || $self->{ 'format_type' }))
{
- if (!$self->{ '_is_in_from' })
+ $self->{ '_is_in_using' } = 1;
+ if (!$self->{ '_is_in_from' })
{
- $self->_new_line;
- }
+ $self->_over($token,$last) if ($self->{ '_is_in_operator' });
+ $self->_new_line($token,$last) if (uc($last) ne 'EXCLUDE');
+ }
else
{
- # USING from join clause disable line break
- $self->{ 'no_break' } = 1;
- $self->{ '_is_in_function' }++;
+ # USING from join clause disable line break
+ #$self->{ 'no_break' } = 1;
+ $self->{ '_is_in_function' }++;
+ }
+ $self->_add_token($token);
+ }
+
+ elsif ($token =~ /^EXCLUDE$/i)
+ {
+ if ($last !~ /^(FOLLOWING|ADD)$/i or $self->_next_token !~ /^USING$/i) {
+ $self->_new_line($token,$last) if ($last !~ /^(FOLLOWING|ADD)$/i);
}
- $self->_add_token($token);
- }
- elsif ($token =~ /^\\\S/)
+ $self->_add_token( $token );
+ $self->{ '_is_in_using' } = 1;
+ }
+
+ elsif ($token =~ /^\\\S/)
{
- # treat everything starting with a \ and at least one character as psql meta command.
- $self->_add_token( $token );
- $self->_new_line;
- }
+ # treat everything starting with a \ and at least one character as psql meta command.
+ $self->_add_token( $token );
+ $self->_new_line($token,$last);
+ }
- elsif ($token =~ /^ADD$/i && ($self->{ '_current_sql_stmt' } eq 'SEQUENCE'
+ elsif ($token =~ /^ADD|DROP$/i && ($self->{ '_current_sql_stmt' } eq 'SEQUENCE'
|| $self->{ '_current_sql_stmt' } eq 'ALTER'))
{
- $self->_new_line;
- $self->_over;
- $self->_add_token($token);
- }
+ if ($self->_next_token !~ /^NOT|NULL|DEFAULT$/i and (not defined $last or !$self->{ '_is_in_alter' } or $last ne '(')) {
+ $self->_new_line($token,$last);
+ if ($self->{ '_is_in_alter' } < 2) {
+ $self->_over($token,$last);
+ }
+ }
+ $self->_add_token($token, $last);
+ $self->{ '_is_in_alter' }++ if ($self->{ '_is_in_alter' } == 1);
+ }
- elsif ($token =~ /^INCREMENT$/i && $self->{ '_current_sql_stmt' } eq 'SEQUENCE')
+ elsif ($token =~ /^INCREMENT$/i && $self->{ '_current_sql_stmt' } eq 'SEQUENCE')
{
- $self->_new_line;
- $self->_add_token($token);
- }
+ $self->_new_line($token,$last);
+ $self->_add_token($token);
+ }
- elsif ($token =~ /^NO$/i and $self->_next_token =~ /^(MINVALUE|MAXVALUE)$/i)
+ elsif ($token =~ /^NO$/i and $self->_next_token =~ /^(MINVALUE|MAXVALUE)$/i)
{
- $self->_new_line;
- $self->_add_token($token);
- }
+ $self->_new_line($token,$last);
+ $self->_add_token($token);
+ }
- elsif (uc($last) ne 'NO' and $token =~ /^(MINVALUE|MAXVALUE)$/i)
+ elsif ($last !~ /^(\(|NO)$/i and $token =~ /^(MINVALUE|MAXVALUE)$/i)
{
- $self->_new_line;
- $self->_add_token($token);
- }
+ $self->_new_line($token,$last);
+ $self->_add_token($token);
+ }
- elsif ($token =~ /^CACHE$/i)
+ elsif ($token =~ /^CACHE$/i)
{
- $self->_new_line;
- $self->_add_token($token);
- }
+ $self->_new_line($token,$last);
+ $self->_add_token($token);
+ }
- else
+ else
{
- if ($last =~ /^(?:SEQUENCE)$/i and $self->_next_token !~ /^OWNED$/i)
- {
- $self->_add_token( $token );
- $self->_new_line;
- $self->_over;
+ if ($self->{ '_fct_code_delimiter' } and $self->{ '_fct_code_delimiter' } =~ /^'.*'$/) {
+ $self->{ '_fct_code_delimiter' } = "";
}
- else
+ # special case with comment
+ if ($token =~ /(?:\s*--)[\ \t\S]*/s)
{
- if (defined $last && $last eq ')' && (!defined $self->_next_token || $self->_next_token ne ';'))
- {
- if (!$self->{ '_parenthesis_level' } && $self->{ '_is_in_from' })
- {
- $self->{ '_level' } = pop(@{ $self->{ '_level_parenthesis' } }) || 1;
- }
+ $token =~ s/^(\s*)(--.*)/$2/s;
+ my $start = $1 || '';
+ if ($start =~ /\n/s) {
+ $self->_new_line($token,$last), $self->_add_token('') if (defined $last and $last eq ';' and $self->{ 'content' } !~ /\n$/s);
+ $self->_new_line($token,$last);
}
- $self->_add_token( $token, $last );
- if (defined $last && uc($last) eq 'LANGUAGE' && (!defined $self->_next_token || $self->_next_token ne ';'))
- {
- $self->_new_line;
+ $token =~ s/\s+$//s;
+ $token =~ s/^\s+//s;
+ $self->_add_token( $token );
+ $self->_new_line($token,$last) if ($start || $self->{ 'content' } !~ /\n/s);
+ # Add extra newline after the last comment if we are not in a block or a statement
+ if (defined $self->_next_token and $self->_next_token !~ /^\s*--/) {
+ $self->{ 'content' } .= "\n" if ($self->{ '_is_in_block' } == -1
+ and !$self->{ '_is_in_declare' } and !$self->{ '_fct_code_delimiter' }
+ and !$self->{ '_current_sql_stmt' }
+ and defined $last and $self->_is_comment($last)
+ );
}
- }
- }
+ $last = $token;
+ next;
+ }
- $last = $token;
- $pos++;
+ if ($last =~ /^(?:SEQUENCE)$/i and $self->_next_token !~ /^(OWNED|;)$/i)
+ {
+ $self->_add_token( $token );
+ $self->_new_line($token,$last);
+ $self->_over($token,$last);
+ }
+ else
+ {
+ if (defined $last && $last eq ')' && (!defined $self->_next_token || $self->_next_token ne ';'))
+ {
+ if (!$self->{ '_parenthesis_level' } && $self->{ '_is_in_from' })
+ {
+ $self->{ '_level' } = pop(@{ $self->{ '_level_parenthesis' } }) || 1;
+ }
+ }
+ $self->_add_token( $token, $last );
+ if (defined $last && uc($last) eq 'LANGUAGE' && (!defined $self->_next_token || $self->_next_token ne ';'))
+ {
+ $self->_new_line($token,$last);
+ }
+ }
+ }
+
+ $last = $token;
+ $pos++;
}
- $self->_new_line;
+ $self->_new_line();
return;
}
sub _add_token {
my ( $self, $token, $last_token ) = @_;
- if ( $self->{ 'wrap' } ) {
- my $wrap;
- if ( $self->_is_keyword( $token ) ) {
- $wrap = $self->{ 'wrap' }->{ 'keywords' };
- }
- elsif ( $self->_is_constant( $token ) ) {
- $wrap = $self->{ 'wrap' }->{ 'constants' };
- }
+ if ($DEBUG) {
+ my ($package, $filename, $line) = caller;
+ print STDERR "DEBUG_ADD: line: $line => last=", ($last_token||''), ", token=$token\n";
+ }
- if ( $wrap ) {
- $token = $wrap->[ 0 ] . $token . $wrap->[ 1 ];
- }
+ if ( $self->{ 'wrap' } ) {
+ my $wrap;
+ if ( $self->_is_keyword( $token ) ) {
+ $wrap = $self->{ 'wrap' }->{ 'keywords' };
+ }
+ elsif ( $self->_is_constant( $token ) ) {
+ $wrap = $self->{ 'wrap' }->{ 'constants' };
+ }
+
+ if ( $wrap ) {
+ $token = $wrap->[ 0 ] . $token . $wrap->[ 1 ];
+ }
}
my $last_is_dot = defined( $last_token ) && $last_token eq '.';
my $sp = $self->_indent;
- if ( !$self->_is_punctuation( $token ) and !$last_is_dot) {
- if ( (!defined($last_token) || $last_token ne '(') && $token ne ')' && ($token !~ /^::/) ) {
- $self->{ 'content' } .= $sp if ($token ne ')'
- && defined($last_token)
- && $last_token ne '::'
+ if ( !$self->_is_punctuation( $token ) and !$last_is_dot)
+ {
+ if ( (!defined($last_token) || $last_token ne '(') && $token ne ')' && $token !~ /^::/ ) {
+ $self->{ 'content' } .= $sp if ($token ne ')'
+ && defined($last_token)
+ && $last_token ne '::'
+ && $last_token ne '['
&& ($token ne '(' || !$self->_is_function( $last_token ) || $self->{ '_is_in_type' })
- );
- $self->{ 'content' } .= $sp if (!defined($last_token) && $token);
- } elsif ( $self->{ '_is_in_create' } == 2 && defined($last_token)) {
- $self->{ 'content' } .= $sp if ($last_token ne '::' and ($last_token ne '(' || !$self->{ '_is_in_index' }));
- } elsif (defined $last_token) {
- $self->{ 'content' } .= $sp if ($last_token eq '(' && $self->{ '_is_in_type' });
- }
- if ($self->_is_comment($token)) {
- my @lines = split(/\n/, $token);
- for (my $i = 1; $i <= $#lines; $i++) {
- if ($lines[$i] =~ /^\s*\*/) {
- $lines[$i] =~ s/^\s*\*/$sp */;
- } elsif ($lines[$i] =~ /^\s+[^\*]/) {
- $lines[$i] =~ s/^\s+/$sp /;
- }
- }
- $token = join("\n", @lines);
- } else {
- $token =~ s/\n/\n$sp/gs;
- }
+ );
+ $self->{ 'content' } .= $sp if (!defined($last_token) && $token);
+ } elsif ( defined $last_token && $last_token eq '(' && $token ne ')' && $token !~ /^::/ && !$self->{'wrap_after'} && $self->{ '_is_in_with' } == 1) {
+ $self->{ 'content' } .= $sp;
+ } elsif ( $self->{ '_is_in_create' } == 2 && defined($last_token)) {
+ $self->{ 'content' } .= $sp if ($last_token ne '::' and !$self->{ '_is_in_partition' }
+ and !$self->{ '_is_in_policy' }
+ and !$self->{ '_is_in_trigger' }
+ and !$self->{ '_is_in_aggregate' }
+ and ($last_token ne '(' || !$self->{ '_is_in_index' }));
+ } elsif (defined $last_token and (!$self->{ '_is_in_operator' } or !$self->{ '_is_in_alter' })) {
+ $self->{ 'content' } .= $sp if ($last_token eq '(' && ($self->{ '_is_in_type' } or ($self->{ '_is_in_operator' } and !$self->_is_type($token))));
+ } elsif ($token eq ')' and $self->{ '_is_in_block' } >= 0 && $self->{ '_is_in_create' }) {
+ $self->{ 'content' } .= $sp;
+ }
+ if ($self->_is_comment($token)) {
+ my @lines = split(/\n/, $token);
+ for (my $i = 1; $i <= $#lines; $i++) {
+ if ($lines[$i] =~ /^\s*\*/) {
+ $lines[$i] =~ s/^\s*\*/$sp */;
+ } elsif ($lines[$i] =~ /^\s+[^\*]/) {
+ $lines[$i] =~ s/^\s+/$sp /;
+ }
+ }
+ $token = join("\n", @lines);
+ } else {
+ $token =~ s/\n/\n$sp/gs;
+ }
}
- #lowercase/uppercase keywords
- if ( $self->{ 'uc_keywords' } && $self->_is_keyword( $token ) ) {
- $token = lc( $token ) if ( $self->{ 'uc_keywords' } == 1 );
- $token = uc( $token ) if ( $self->{ 'uc_keywords' } == 2 );
- $token = ucfirst( lc( $token ) ) if ( $self->{ 'uc_keywords' } == 3 );
+ my $next_token = $self->_next_token || '';
+
+ # lowercase/uppercase keywords taking care of function with same name
+ if ($self->_is_keyword( $token, $next_token, $last_token ) && (!$self->_is_function( $token ) || $next_token ne '(')) {
+ $token = lc( $token ) if ( $self->{ 'uc_keywords' } == 1 );
+ $token = uc( $token ) if ( $self->{ 'uc_keywords' } == 2 );
+ $token = ucfirst( lc( $token ) ) if ( $self->{ 'uc_keywords' } == 3 );
}
+ else
+ {
- # lowercase/uppercase functions
- if ( $self->{ 'uc_functions' } && ( my $fct = $self->_is_function( $token ) ) ) {
- $token =~ s/$fct/\L$fct\E/i if ( $self->{ 'uc_functions' } == 1 );
- $token =~ s/$fct/\U$fct\E/i if ( $self->{ 'uc_functions' } == 2 );
- $fct = ucfirst( lc( $fct ) );
- $token =~ s/$fct/$fct/i if ( $self->{ 'uc_functions' } == 3 );
+ # lowercase/uppercase known functions or words followed by an open parenthesis
+ # if the token is not a keyword, an open parenthesis or a comment
+ my $fct = $self->_is_function( $token ) || '';
+ if (($fct && $next_token eq '(')
+ || (!$self->_is_keyword( $token ) && !$next_token eq '('
+ && $token ne '(' && !$self->_is_comment( $token )) ) {
+ $token =~ s/$fct/\L$fct\E/i if ( $self->{ 'uc_functions' } == 1 );
+ $token =~ s/$fct/\U$fct\E/i if ( $self->{ 'uc_functions' } == 2 );
+ $fct = ucfirst( lc( $fct ) );
+ $token =~ s/$fct/$fct/i if ( $self->{ 'uc_functions' } == 3 );
+ }
}
# Add formatting for HTML output
if ( $self->{ 'colorize' } && $self->{ 'format' } eq 'html' ) {
- $token = $self->highlight_code($token, $last_token, $self->_next_token);
+ $token = $self->highlight_code($token, $last_token, $next_token);
}
$self->{ 'content' } .= $token;
- $self->{ 'content' } =~ s/\(\s+\(/\(\(/gs;
# This can't be the beginning of a new line anymore.
$self->{ '_new_line' } = 0;
=cut
sub _over {
- my ( $self ) = @_;
+ my ( $self, $token, $last ) = @_;
+
+ if ($DEBUG) {
+ my ($package, $filename, $line) = caller;
+ print STDERR "DEBUG_OVER: line: $line => last=$last, token=$token\n";
+ }
++$self->{ '_level' };
}
=cut
sub _back {
- my ( $self ) = @_;
+ my ( $self, $token, $last ) = @_;
+ if ($DEBUG) {
+ my ($package, $filename, $line) = caller;
+ print STDERR "DEBUG_BACK: line: $line => last=$last, token=$token\n";
+ }
--$self->{ '_level' } if ( $self->{ '_level' } > 0 );
}
my ( $self ) = @_;
if ( $self->{ '_new_line' } ) {
- return $self->{ 'space' } x ( $self->{ 'spaces' } * $self->{ '_level' } );
+ return $self->{ 'space' } x ( $self->{ 'spaces' } * ( $self->{ '_level' } // 0 ) );
}
else {
- return $self->{ 'space' };
+ return $self->{ 'space' };
}
}
=cut
sub _new_line {
- my ( $self ) = @_;
+ my ( $self, $token, $last ) = @_;
+
+ if ($DEBUG and defined $token) {
+ my ($package, $filename, $line) = caller;
+ print STDERR "DEBUG_NL: line: $line => last=", ($last||''), ", token=$token\n";
+ }
$self->{ 'content' } .= $self->{ 'break' } unless ( $self->{ '_new_line' } );
$self->{ '_new_line' } = 1;
=cut
sub _is_keyword {
- my ( $self, $token ) = @_;
+ my ( $self, $token, $next_token, $last_token ) = @_;
+
+ # Fix some false positive
+ if (defined $next_token) {
+ return 0 if (uc($token) eq 'EVENT' and uc($next_token) ne 'TRIGGER');
+ }
return ~~ grep { $_ eq uc( $token ) } @{ $self->{ 'keywords' } };
}
+=head2 _is_type
+
+Check if a token is a known SQL type
+
+=cut
+
+sub _is_type {
+ my ( $self, $token ) = @_;
+
+ return ~~ grep { $_ eq uc( $token ) } @{ $self->{ 'types' } };
+}
+
+
+sub _is_sql_keyword {
+ my ( $self, $token ) = @_;
+
+ return ~~ grep { $_ eq uc( $token ) } @{ $self->{ 'sql_keywords' } };
+}
+
+
=head2 _is_comment
Check if a token is a SQL or C style comment
Check if a token is a known SQL function.
-Code lifted from SQL::Beautify
+Code lifted from SQL::Beautify and rewritten to check one long regexp instead of a lot of small ones.
=cut
sub _is_function {
my ( $self, $token ) = @_;
- my @ret = grep( $token =~ /\b[\.]*$_$/i, @{ $self->{ 'functions' } } );
-
- return $ret[ 0 ];
+ if ( $token =~ $self->{ 'functions_re' } ) {
+ return $1;
+ } else {
+ return undef;
+ }
}
=head2 add_keywords
my $self = shift;
for my $keyword ( @_ ) {
- push @{ $self->{ 'keywords' } }, ref( $keyword ) ? @{ $keyword } : $keyword;
+ push @{ $self->{ 'keywords' } }, ref( $keyword ) ? @{ $keyword } : $keyword;
}
}
+=head2 _re_from_list
+
+Create compiled regexp from prefix, suffix and and a list of values to match.
+
+=cut
+
+sub _re_from_list {
+ my $prefix = shift;
+ my $suffix = shift;
+ my (@joined_list, $ret_re);
+
+ for my $list_item ( @_ ) {
+ push @joined_list, ref( $list_item ) ? @{ $list_item } : $list_item;
+ }
+
+ $ret_re = "$prefix(" . join('|', @joined_list) . ")$suffix";
+
+ return qr/$ret_re/i;
+}
+
+=head2 _refresh_functions_re
+
+Refresh compiled regexp for functions.
+
+=cut
+
+sub _refresh_functions_re {
+ my $self = shift;
+ $self->{ 'functions_re' } = _re_from_list( '\b[\.]*', '$', @{ $self->{ 'functions' } });
+}
+
=head2 add_functions
Add new functions to highlight.
my $self = shift;
for my $function ( @_ ) {
- push @{ $self->{ 'functions' } }, ref( $function ) ? @{ $function } : $function;
+ push @{ $self->{ 'functions' } }, ref( $function ) ? @{ $function } : $function;
}
+
+ $self->_refresh_functions_re();
}
=head2 add_rule
values %{ $self->{ 'rules' } }; # Reset iterator.
while ( my ( $rule, $list ) = each %{ $self->{ 'rules' } } ) {
- return $rule if ( grep { uc( $token ) eq uc( $_ ) } @$list );
+ return $rule if ( grep { uc( $token ) eq uc( $_ ) } @$list );
}
return;
my ( $self, $rule, $token ) = @_;
my $format = {
- break => sub { $self->_new_line },
- over => sub { $self->_over },
- back => sub { $self->_back },
- token => sub { $self->_add_token( $token ) },
- push => sub { push @{ $self->{ '_level_stack' } }, $self->{ '_level' } },
- pop => sub { $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0 },
- reset => sub { $self->{ '_level' } = 0; @{ $self->{ '_level_stack' } } = (); },
+ break => sub { $self->_new_line() },
+ over => sub { $self->_over() },
+ back => sub { $self->_back() },
+ token => sub { $self->_add_token( $token ) },
+ push => sub { push @{ $self->{ '_level_stack' } }, $self->{ '_level' } },
+ pop => sub { $self->{ '_level' } = pop( @{ $self->{ '_level_stack' } } ) || 0 },
+ reset => sub { $self->{ '_level' } = 0; @{ $self->{ '_level_stack' } } = (); },
};
for ( split /-/, lc $rule ) {
- &{ $format->{ $_ } } if ( $format->{ $_ } );
+ &{ $format->{ $_ } } if ( $format->{ $_ } );
}
}
if ($self->{ 'comma' } eq 'start' and $token eq ',') {
return 0;
}
- return ( $token =~ /^[,;.]$/ );
+ return ( $token =~ /^[,;.\[\]]$/ );
}
=head2 _generate_anonymized_string
# Prevent dates format like DD/MM/YYYY HH24:MI:SS from being anonymized
return $original if $original =~ m{
- \A
- (?:FM|FX|TM)?
- (?:
- HH | HH12 | HH24
- | MI
- | SS
- | MS
- | US
- | SSSS
- | AM | A\.M\. | am | a\.m\.
- | PM | P\.M\. | pm | p\.m\.
- | Y,YYY | YYYY | YYY | YY | Y
- | IYYY | IYY | IY | I
- | BC | B\.C\. | bc | b\.c\.
- | AD | A\.D\. | ad | a\.d\.
- | MONTH | Month | month | MON | Mon | mon | MM
- | DAY | Day | day | DY | Dy | dy | DDD | DD | D
- | W | WW | IW
- | CC
- | J
- | Q
- | RM | rm
- | TZ | tz
- | [\s/:-]
- )+
- (?:TH|th|SP)?
- \z
+ \A
+ (?:FM|FX|TM)?
+ (?:
+ HH | HH12 | HH24
+ | MI
+ | SS
+ | MS
+ | US
+ | SSSS
+ | AM | A\.M\. | am | a\.m\.
+ | PM | P\.M\. | pm | p\.m\.
+ | Y,YYY | YYYY | YYY | YY | Y
+ | IYYY | IYY | IY | I
+ | BC | B\.C\. | bc | b\.c\.
+ | AD | A\.D\. | ad | a\.d\.
+ | MONTH | Month | month | MON | Mon | mon | MM
+ | DAY | Day | day | DY | Dy | dy | DDD | DD | D
+ | W | WW | IW
+ | CC
+ | J
+ | Q
+ | RM | rm
+ | TZ | tz
+ | [\s/:-]
+ )+
+ (?:TH|th|SP)?
+ \z
};
# Prevent interval from being anonymized
unless ( $cache->{ $original } ) {
- # Actual anonymized version generation
- $cache->{ $original } = join( '', map { $chars[ rand @chars ] } 1 .. 10 );
+ # Actual anonymized version generation
+ $cache->{ $original } = join( '', map { $chars[ rand @chars ] } 1 .. 10 );
}
return $cache->{ $original };
# Anonymize each values
$query =~ s{
- ([^\s\']+[\s\(]*) # before
- '([^']*)' # original
- ([\)]*::\w+)? # after
+ ([^\s\']+[\s\(]*) # before
+ '([^']*)' # original
+ ([\)]*::\w+)? # after
}{$1 . "'" . $self->_generate_anonymized_string($1, $2, $3) . "'" . ($3||'')}xeg;
$query =~ s/\$EMPTYSTRING\$/''/gs;
=item colorize => 1
+=item format_type => 0
+
+=item wrap_limit => 0
+
+=item wrap_after => 0
+
=back
=cut
$self->set_dicts();
# Set some defaults.
- $self->{ 'query' } = '';
+ $self->{ 'query' } = '';
$self->{ 'spaces' } = 4;
- $self->{ 'space' } = ' ';
- $self->{ 'break' } = "\n";
- $self->{ 'wrap' } = {};
- $self->{ 'rules' } = {};
+ $self->{ 'space' } = ' ';
+ $self->{ 'break' } = "\n";
+ $self->{ 'wrap' } = {};
+ $self->{ 'rules' } = {};
$self->{ 'uc_keywords' } = 0;
$self->{ 'uc_functions' } = 0;
$self->{ 'no_comments' } = 0;
$self->{ 'placeholder' } = '';
$self->{ 'keywords' } = $self->{ 'dict' }->{ 'pg_keywords' };
- $self->{ 'functions' } = $self->{ 'dict' }->{ 'pg_functions' };
+ $self->{ 'types' } = $self->{ 'dict' }->{ 'pg_types' };
+ $self->{ 'functions' } = ();
+ push(@{ $self->{ 'functions' } }, keys %{ $self->{ 'dict' }->{ 'pg_functions' } });
+ $self->_refresh_functions_re();
$self->{ 'separator' } = '';
- $self->{ 'comma' } = 'end';
+ $self->{ 'comma' } = 'end';
$self->{ 'format' } = 'text';
$self->{ 'colorize' } = 1;
+ $self->{ 'format_type' } = 0;
+ $self->{ 'wrap_limit' } = 0;
+ $self->{ 'wrap_after' } = 0;
return;
}
my $format = shift;
if ( grep(/^$format$/i, 'text', 'html') ) {
- $self->{ 'format' } = lc($format);
+ $self->{ 'format' } = lc($format);
return 1;
}
return 0;
# First load it all as "my" variables, to make it simpler to modify/map/grep/add
# Afterwards, when everything is ready, put it in $self->{'dict'}->{...}
- my @pg_keywords = map { uc } qw(
- ADD AFTER ALL ALTER ANALYSE ANALYZE AND ANY ARRAY AS ASC ASYMMETRIC AUTHORIZATION AUTO_INCREMENT
- BACKWARD BEFORE BEGIN BERNOULLI BETWEEN BINARY BOTH BY BY CACHE CASCADE CASE CAST CHECK CHECKPOINT
- CLOSE CLUSTER COLLATE COLLATION COLUMN COMMENT COMMIT COMMITTED CONCURRENTLY CONFLICT CONSTRAINT
- CONSTRAINT CONTINUE COPY COST CREATE CROSS CUBE CURRENT_DATE CURRENT_ROLE CURRENT_TIME CURRENT_TIMESTAMP
- CURRENT_USER CURSOR CYCLE DATABASE DEALLOCATE DECLARE DEFAULT DEFERRABLE DEFERRED DEFINER DELETE DELIMITER
- DESC DISTINCT DO DOMAIN DROP EACH ELSE ENCODING END EXCEPT EXCLUDING EXECUTE EXISTS EXPLAIN EXTENSION FALSE
- FETCH FIRST FOR FOREIGN FORWARD FREEZE FROM FULL FUNCTION GRANT GROUP GROUPING HAVING IF ILIKE IMMUTABLE IN
- INCLUDING INCREMENT INDEX INHERITS INITIALLY INNER INOUT INSERT INSTEAD INTERSECT INTO INVOKER IS ISNULL
- ISOLATION JOIN KEY LANGUAGE LAST LATERAL LC_COLLATE LC_CTYPE LEADING LEAKPROOF LEFT LIKE LIMIT LISTEN LOAD
- LOCALTIME LOCALTIMESTAMP LOCATION LOCK LOCKED LOGGED LOGIN LOOP MAPPING MAXVALUE MINVALUE MOVE NATURAL NEXT
- NO NOCREATEDB NOCREATEROLE NOSUPERUSER NOT NOTIFY NOTNULL NOWAIT NULL OIDS ON ONLY OPEN OPERATOR OR ORDER
- OUTER OVER OVERLAPS OWNER PARTITION PASSWORD PERFORM PLACING POLICY PRECEDING PREPARE PRIMARY PROCEDURE
- REASSIGN RECURSIVE REFERENCES REINDEX RENAME REPEATABLE REPLACE REPLICA RESET RESTART RETURN RETURNING
- RETURNS RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP ROWS RULE SAVEPOINT SCHEMA SCROLL SECURITY SELECT SEQUENCE
- SEQUENCE SERIALIZABLE SERVER SESSION_USER SET SETOF SETS SHOW SIMILAR SKIP SNAPSHOT SOME STABLE START STRICT
- SYMMETRIC SYSTEM TABLE TABLESAMPLE TABLESPACE TEMPLATE TEMPORARY THEN TO TRAILING TRANSACTION TRIGGER TRUE
- TRUNCATE TYPE UNBOUNDED UNCOMMITTED UNION UNIQUE UNLISTEN UNLOCK UNLOGGED UPDATE USER USING VACUUM VALUES
- VARIADIC VERBOSE VIEW VOLATILE WHEN WHERE WINDOW WITH XOR ZEROFILL
+ my @pg_keywords = map { uc } qw(
+ ADD AFTER AGGREGATE ALL ALTER ANALYSE ANALYZE AND ANY ARRAY AS ASC ASYMMETRIC AUTHORIZATION ATTACH AUTO_INCREMENT
+ BACKWARD BEFORE BEGIN BERNOULLI BETWEEN BINARY BOTH BY CACHE CASCADE CASE CAST CHECK CHECKPOINT CLOSE CLUSTER
+ COLLATE COLLATION COLUMN COMMENT COMMIT COMMITTED CONCURRENTLY CONFLICT CONSTRAINT CONSTRAINT CONTINUE COPY
+ COST COSTS CREATE CROSS CUBE CURRENT CURRENT_DATE CURRENT_ROLE CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR
+ CYCLE DATABASE DEALLOCATE DECLARE DEFAULT DEFERRABLE DEFERRED DEFINER DELETE DELIMITER DESC DETACH EVENT DISTINCT
+ DO DOMAIN DROP EACH ELSE ENCODING END EXCEPT EXCLUDE EXCLUDING EXECUTE EXISTS EXPLAIN EXTENSION FALSE FETCH FILTER
+ FIRST FOLLOWING FOR FOREIGN FORWARD FREEZE FROM FULL FUNCTION GENERATED GRANT GROUP GROUPING HAVING HASHES HASH
+ IDENTITY IF ILIKE IMMUTABLE IN INCLUDING INCREMENT INDEX INHERITS INITIALLY INNER INOUT INSERT INSTEAD
+ INTERSECT INTO INVOKER IS ISNULL ISOLATION JOIN KEY LANGUAGE LAST LATERAL LC_COLLATE LC_CTYPE LEADING
+ LEAKPROOF LEFT LEFTARG LIKE LIMIT LIST LISTEN LOAD LOCALTIME LOCALTIMESTAMP LOCATION LOCK LOCKED LOGGED LOGIN
+ LOOP MAPPING MATCH MAXVALUE MERGES MINVALUE MODULUS MOVE NATURAL NEXT ORDINALITY
+ NO NOCREATEDB NOCREATEROLE NOSUPERUSER NOT NOTIFY NOTNULL NOWAIT NULL OFF OF OIDS ON ONLY OPEN OPERATOR OR ORDER
+ OUTER OVER OVERLAPS OWNER PARTITION PASSWORD PERFORM PLACING POLICY PRECEDING PREPARE PRIMARY PROCEDURE RANGE
+ REASSIGN RECURSIVE REFERENCES REINDEX REMAINDER RENAME REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURN RETURNING
+ RETURNS RETURNS REVOKE RIGHT RIGHTARG ROLE ROLLBACK ROLLUP ROWS ROW RULE SAVEPOINT SCHEMA SCROLL SECURITY SELECT SEQUENCE
+ SEQUENCE SERIALIZABLE SERVER SESSION_USER SET SETOF SETS SHOW SIMILAR SKIP SNAPSHOT SOME STABLE START STRICT
+ SYMMETRIC SYSTEM TABLE TABLESAMPLE TABLESPACE TEMPLATE TEMPORARY THEN TO TRAILING TRANSACTION TRIGGER TRUE
+ TRUNCATE TYPE UNBOUNDED UNCOMMITTED UNION UNIQUE UNLISTEN UNLOCK UNLOGGED UPDATE USER USING VACUUM VALUES
+ VARIADIC VERBOSE VIEW VOLATILE WHEN WHERE WINDOW WITH WITHIN WORK XOR ZEROFILL
+ CALL GROUPS INCLUDE OTHERS PROCEDURES ROUTINE ROUTINES TIES READ_ONLY SHAREABLE READ_WRITE
+ BASETYPE SFUNC STYPE SFUNC1 STYPE1 SSPACE FINALFUNC FINALFUNC_EXTRA FINALFUNC_MODIFY COMBINEFUNC SERIALFUNC DESERIALFUNC
+ INITCOND MSFUNC MINVFUNC MSTYPE MSSPACE MFINALFUNC MFINALFUNC_EXTRA MFINALFUNC_MODIFY MINITCOND SORTOP
+ );
+
+ my @pg_types = qw(
+ BIGINT BIGSERIAL BIT BOOLEAN BOX BYTEA CHARACTER CIDR CIRCLE DATE DOUBLE INET INT INTEGER INTERVAL JSON
+ JSONB LINE LSEG MACADDR MACADDR8 MONEY NUMERIC PATH PG_LSN POINT POLYGON REAL SMALLINT SMALLSERIAL
+ SERIAL TEXT TIME TIMESTAMP TSQUERY TSVECTOR TXID_SNAPSHOT UUID XML INT2 INT4 INT8 VARYING
);
my @sql_keywords = map { uc } qw(
- ABORT ABSOLUTE ACCESS ACTION ADMIN AGGREGATE ALSO ALWAYS ASSERTION ASSIGNMENT AT ATTRIBUTE BIGINT BOOLEAN
- CALLED CASCADED CATALOG CHAIN CHANGE CHARACTER CHARACTERISTICS COLUMNS COMMENTS CONFIGURATION
- CONNECTION CONSTRAINTS CONTENT CONVERSION CSV CURRENT DATA DATABASES DAY DEC DECIMAL DEFAULTS DELAYED
- DELIMITERS DESCRIBE DICTIONARY DISABLE DISCARD DOCUMENT DOUBLE ENABLE ENCLOSED ENCRYPTED ENUM ESCAPE ESCAPED
- EXCLUDE EXCLUSIVE EXTERNAL FIELD FIELDS FLOAT FLUSH FOLLOWING FORCE FUNCTIONS GLOBAL GRANTED GREATEST HANDLER
- HEADER HOLD HOUR IDENTIFIED IDENTITY IGNORE IMMEDIATE IMPLICIT INDEXES INFILE INHERIT INLINE INPUT INSENSITIVE
- INT INTEGER KEYS KILL LABEL LARGE LEAST LEVEL LINES LOCAL LOW_PRIORITY MATCH MINUTE MODE MODIFY MONTH NAMES
- NATIONAL NCHAR NONE NOTHING NULLIF NULLS OBJECT OF OFF OPERATOR OPTIMIZE OPTION OPTIONALLY OPTIONS OUT OUTFILE
- OWNED PARSER PARTIAL PASSING PLANS PRECISION PREPARED PRESERVE PRIOR PRIVILEGES PROCEDURAL QUOTE RANGE READ
- REAL RECHECK REF REGEXP RELATIVE RELEASE RESTRICT RLIKE ROW SEARCH SECOND SEQUENCES SESSION SHARE SIMPLE
- SMALLINT SONAME STANDALONE STATEMENT STATISTICS STATUS STORAGE STRAIGHT_JOIN SYSID TABLES TEMP TERMINATED
- TREAT TRUSTED TYPES UNENCRYPTED UNKNOWN UNSIGNED UNTIL USE VALID VALIDATE VALIDATOR VALUE VARIABLES VARYING
- WHITESPACE WITHOUT WORK WRAPPER WRITE XMLATTRIBUTES YEAR YES ZONE
- );
+ ABORT ABSOLUTE ACCESS ACTION ADMIN ALSO ALWAYS ASSERTION ASSIGNMENT AT ATTRIBUTE BIGINT BOOLEAN
+ CALLED CASCADED CATALOG CHAIN CHANGE CHARACTER CHARACTERISTICS COLUMNS COMMENTS CONFIGURATION
+ CONNECTION CONSTRAINTS CONTENT CONVERSION CSV CURRENT DATA DATABASES DAY DEC DECIMAL DEFAULTS DELAYED
+ DELIMITERS DESCRIBE DICTIONARY DISABLE DISCARD DOCUMENT DOUBLE ENABLE ENCLOSED ENCRYPTED ENUM ESCAPE ESCAPED
+ EXCLUSIVE EXTERNAL FIELD FIELDS FLOAT FLUSH FOLLOWING FORCE FUNCTIONS GLOBAL GRANTED GREATEST HANDLER
+ HEADER HOLD HOUR IDENTIFIED IGNORE IMMEDIATE IMPLICIT INDEXES INFILE INHERIT INLINE INPUT INSENSITIVE
+ INT INTEGER KEYS KILL LABEL LARGE LEAST LEVEL LINES LOCAL LOW_PRIORITY MATCH MINUTE MODE MODIFY MONTH NAMES
+ NATIONAL NCHAR NONE NOTHING NULLIF NULLS OBJECT OFF OPERATOR OPTIMIZE OPTION OPTIONALLY OPTIONS OUT OUTFILE
+ OWNED PARSER PARTIAL PASSING PLANS PRECISION PREPARED PRESERVE PRIOR PRIVILEGES PROCEDURAL QUOTE READ
+ REAL RECHECK REF REGEXP RELATIVE RELEASE RLIKE ROW SEARCH SECOND SEQUENCES SESSION SHARE SIMPLE
+ SMALLINT SONAME STANDALONE STATEMENT STATISTICS STATUS STORAGE STRAIGHT_JOIN SYSID TABLES TEMP TERMINATED
+ TREAT TRUSTED TYPES UNENCRYPTED UNKNOWN UNSIGNED UNTIL USE VALID VALIDATE VALIDATOR VALUE VARIABLES VARYING
+ WHITESPACE WITHOUT WORK WRAPPER WRITE XMLATTRIBUTES YEAR YES ZONE
+ );
my @redshift_keywords = map { uc } qw(
- AES128 AES256 ALLOWOVERWRITE BACKUP BLANKSASNULL BYTEDICT BZIP2 CREDENTIALS CURRENT_USER_ID DEFLATE DEFRAG
- DELTA DELTA32K DISABLE DISTKEY EMPTYASNULL ENABLE ENCODE ENCRYPT ENCRYPTION EXPLICIT GLOBALDICT256
- GLOBALDICT64K GZIP INTERLEAVED LUN LUNS LZO LZOP MINUS MOSTLY13 MOSTLY32 MOSTLY8 NEW OFFLINE OFFSET OID OLD
- PARALLEL PERCENT PERMISSIONS RAW READRATIO RECOVER REJECTLOG RESORT RESPECT RESTORE SORTKEY SYSDATE TAG TDES
- TEXT255 TEXT32K TIMESTAMP TOP TRUNCATECOLUMNS WALLET
- );
+ AES128 AES256 ALLOWOVERWRITE BACKUP BLANKSASNULL BYTEDICT BZIP2 CREDENTIALS CURRENT_USER_ID DEFLATE DEFRAG
+ DELTA DELTA32K DISABLE DISTKEY EMPTYASNULL ENABLE ENCODE ENCRYPT ENCRYPTION EXPLICIT GLOBALDICT256
+ GLOBALDICT64K GZIP INTERLEAVED LUN LUNS LZO LZOP MINUS MOSTLY13 MOSTLY32 MOSTLY8 NEW OFFLINE OFFSET OID OLD
+ PARALLEL PERCENT PERMISSIONS RAW READRATIO RECOVER REJECTLOG RESORT RESPECT RESTORE SORTKEY SYSDATE TAG TDES
+ TEXT255 TEXT32K TIMESTAMP TOP TRUNCATECOLUMNS WALLET
+ );
for my $k ( @pg_keywords ) {
- next if grep { $k eq $_ } @sql_keywords;
- push @sql_keywords, $k;
+ next if grep { $k eq $_ } @sql_keywords;
+ push @sql_keywords, $k;
}
for my $k ( @redshift_keywords ) {
- next if grep { $k eq $_ } @sql_keywords;
- push @sql_keywords, $k;
+ next if grep { $k eq $_ } @sql_keywords;
+ push @sql_keywords, $k;
}
my @pg_functions = map { lc } qw(
- ascii age bit_length btrim cast char_length character_length coalesce convert chr current_date current_time current_timestamp
- count decode date_part date_trunc encode extract get_byte get_bit initcap isfinite interval justify_hours justify_days
- lower length lpad ltrim localtime localtimestamp md5 now octet_length overlay position pg_client_encoding
- quote_ident quote_literal repeat replace rpad rtrim substring split_part strpos substr set_byte set_bit
- trim to_ascii to_hex translate to_char to_date to_timestamp to_number timeofday upper
- abbrev abs abstime abstimeeq abstimege abstimegt abstimein abstimele
- abstimelt abstimene abstimeout abstimerecv abstimesend aclcontains acldefault
- aclexplode aclinsert aclitemeq aclitemin aclitemout aclremove acos
- any_in any_out anyarray_in anyarray_out anyarray_recv anyarray_send anyelement_in
- anyelement_out anyenum_in anyenum_out anynonarray_in anynonarray_out anyrange_in anyrange_out
- anytextcat area areajoinsel areasel armor array_agg array_agg_finalfn
- array_agg_transfn array_append array_cat array_dims array_eq array_fill array_ge
- array_gt array_in array_larger array_le array_length array_lower array_lt
- array_ndims array_ne array_out array_prepend array_recv array_send array_smaller
- array_to_json array_to_string array_typanalyze array_upper arraycontained arraycontains arraycontjoinsel
- arraycontsel arrayoverlap ascii_to_mic ascii_to_utf8 asin atan atan2
- avg big5_to_euc_tw big5_to_mic big5_to_utf8 bit bit_and bit_in
- bit_or bit_out bit_recv bit_send bitand bitcat bitcmp
- biteq bitge bitgt bitle bitlt bitne bitnot
- bitor bitshiftleft bitshiftright bittypmodin bittypmodout bitxor bool
- bool_and bool_or booland_statefunc booleq boolge boolgt boolin
- boolle boollt boolne boolor_statefunc boolout boolrecv boolsend
- box box_above box_above_eq box_add box_below box_below_eq box_center
- box_contain box_contain_pt box_contained box_distance box_div box_eq box_ge
- box_gt box_in box_intersect box_le box_left box_lt box_mul
- box_out box_overabove box_overbelow box_overlap box_overleft box_overright box_recv
- box_right box_same box_send box_sub bpchar bpchar_larger bpchar_pattern_ge
- bpchar_pattern_gt bpchar_pattern_le bpchar_pattern_lt bpchar_smaller bpcharcmp bpchareq bpcharge
- bpchargt bpchariclike bpcharicnlike bpcharicregexeq bpcharicregexne bpcharin bpcharle
- bpcharlike bpcharlt bpcharne bpcharnlike bpcharout bpcharrecv bpcharregexeq
- bpcharregexne bpcharsend bpchartypmodin bpchartypmodout broadcast btabstimecmp btarraycmp
- btbeginscan btboolcmp btbpchar_pattern_cmp btbuild btbuildempty btbulkdelete btcanreturn
- btcharcmp btcostestimate btendscan btfloat48cmp btfloat4cmp btfloat4sortsupport btfloat84cmp
- btfloat8cmp btfloat8sortsupport btgetbitmap btgettuple btinsert btint24cmp btint28cmp
- btint2cmp btint2sortsupport btint42cmp btint48cmp btint4cmp btint4sortsupport btint82cmp
- btint84cmp btint8cmp btint8sortsupport btmarkpos btnamecmp btnamesortsupport btoidcmp
- btoidsortsupport btoidvectorcmp btoptions btrecordcmp btreltimecmp btrescan btrestrpos
- bttext_pattern_cmp bttextcmp bttidcmp bttintervalcmp btvacuumcleanup bytea_string_agg_finalfn bytea_string_agg_transfn
- byteacat byteacmp byteaeq byteage byteagt byteain byteale
- bytealike bytealt byteane byteanlike byteaout bytearecv byteasend
- cash_cmp cash_div_cash cash_div_flt4 cash_div_flt8 cash_div_int2 cash_div_int4 cash_eq
- cash_ge cash_gt cash_in cash_le cash_lt cash_mi cash_mul_flt4
- cash_mul_flt8 cash_mul_int2 cash_mul_int4 cash_ne cash_out cash_pl cash_recv
- cash_send cash_words cashlarger cashsmaller cbrt ceil ceiling
- center char chareq charge chargt charin charle
- charlt charne charout charrecv charsend cideq cidin
- cidout cidr cidr_in cidr_out cidr_recv cidr_send cidrecv
- cidsend circle circle_above circle_add_pt circle_below circle_center circle_contain
- circle_contain_pt circle_contained circle_distance circle_div_pt circle_eq circle_ge circle_gt
- circle_in circle_le circle_left circle_lt circle_mul_pt circle_ne circle_out
- circle_overabove circle_overbelow circle_overlap circle_overleft circle_overright circle_recv circle_right
- circle_same circle_send circle_sub_pt clock_timestamp close_lb close_ls close_lseg
- close_pb close_pl close_ps close_sb close_sl col_description concat
- concat_ws contjoinsel contsel convert_from convert_to corr cos
- cot covar_pop covar_samp crypt cstring_in cstring_out cstring_recv
- cstring_send cume_dist current_database current_query current_schema current_schemas current_setting
- current_user currtid currtid2 currval date date_cmp date_cmp_timestamp date_cmp_timestamptz date_eq
- date_eq_timestamp date_eq_timestamptz date_ge date_ge_timestamp date_ge_timestamptz date_gt date_gt_timestamp
- date_gt_timestamptz date_in date_larger date_le date_le_timestamp date_le_timestamptz date_lt
- date_lt_timestamp date_lt_timestamptz date_mi date_mi_interval date_mii date_ne date_ne_timestamp
- date_ne_timestamptz date_out date_pl_interval date_pli date_recv date_send date_smaller
- date_sortsupport daterange daterange_canonical daterange_subdiff datetime_pl datetimetz_pl
- dblink_connect_u dblink_connect dblink_disconnect dblink_exec dblink_open dblink_fetch dblink_close
- dblink_get_connections dblink_error_message dblink_send_query dblink_is_busy dblink_get_notify dblink_get_result
- dblink_cancel_query dblink_get_pkey dblink_build_sql_insert dblink_build_sql_delete dblink_build_sql_update dblink
-
- dcbrt dearmor decrypt decrypt_iv degrees dense_rank dexp diagonal
- diameter digest dispell_init dispell_lexize dist_cpoly dist_lb dist_pb
- dist_pc dist_pl dist_ppath dist_ps dist_sb dist_sl div
- dlog1 dlog10 domain_in domain_recv dpow dround dsimple_init
- dsimple_lexize dsnowball_init dsnowball_lexize dsqrt dsynonym_init dsynonym_lexize dtrunc
- elem_contained_by_range encrypt encrypt_iv enum_cmp enum_eq enum_first enum_ge
- enum_gt enum_in enum_larger enum_last enum_le enum_lt enum_ne
- enum_out enum_range enum_recv enum_send enum_smaller eqjoinsel eqsel
- euc_cn_to_mic euc_cn_to_utf8 euc_jis_2004_to_shift_jis_2004 euc_jis_2004_to_utf8 euc_jp_to_mic euc_jp_to_sjis euc_jp_to_utf8
- euc_kr_to_mic euc_kr_to_utf8 euc_tw_to_big5 euc_tw_to_mic euc_tw_to_utf8 every exp
- factorial family fdw_handler_in fdw_handler_out first_value float4 float48div
- float48eq float48ge float48gt float48le float48lt float48mi float48mul
- float48ne float48pl float4_accum float4abs float4div float4eq float4ge
- float4gt float4in float4larger float4le float4lt float4mi float4mul
- float4ne float4out float4pl float4recv float4send float4smaller float4um
- float4up float8 float84div float84eq float84ge float84gt float84le
- float84lt float84mi float84mul float84ne float84pl float8_accum float8_avg
- float8_corr float8_covar_pop float8_covar_samp float8_regr_accum float8_regr_avgx float8_regr_avgy float8_regr_intercept
- float8_regr_r2 float8_regr_slope float8_regr_sxx float8_regr_sxy float8_regr_syy float8_stddev_pop float8_stddev_samp
- float8_var_pop float8_var_samp float8abs float8div float8eq float8ge float8gt
- float8in float8larger float8le float8lt float8mi float8mul float8ne
- float8out float8pl float8recv float8send float8smaller float8um float8up
- floor flt4_mul_cash flt8_mul_cash fmgr_c_validator fmgr_internal_validator fmgr_sql_validator format
- format_type gb18030_to_utf8 gbk_to_utf8 gen_random_bytes gen_salt generate_series generate_subscripts
- get_current_ts_config getdatabaseencoding getpgusername gin_cmp_prefix gin_cmp_tslexeme gin_extract_tsquery gin_extract_tsvector
- gin_tsquery_consistent ginarrayconsistent ginarrayextract ginbeginscan ginbuild ginbuildempty ginbulkdelete
- gincostestimate ginendscan gingetbitmap gininsert ginmarkpos ginoptions ginqueryarrayextract
- ginrescan ginrestrpos ginvacuumcleanup gist_box_compress gist_box_consistent gist_box_decompress gist_box_penalty
- gist_box_picksplit gist_box_same gist_box_union gist_circle_compress gist_circle_consistent gist_point_compress gist_point_consistent
- gist_point_distance gist_poly_compress gist_poly_consistent gistbeginscan gistbuild gistbuildempty gistbulkdelete
- gistcostestimate gistendscan gistgetbitmap gistgettuple gistinsert gistmarkpos gistoptions
- gistrescan gistrestrpos gistvacuumcleanup gtsquery_compress gtsquery_consistent gtsquery_decompress gtsquery_penalty
- gtsquery_picksplit gtsquery_same gtsquery_union gtsvector_compress gtsvector_consistent gtsvector_decompress gtsvector_penalty
- gtsvector_picksplit gtsvector_same gtsvector_union gtsvectorin gtsvectorout has_any_column_privilege has_column_privilege
- has_database_privilege has_foreign_data_wrapper_privilege has_function_privilege has_language_privilege has_schema_privilege
- has_sequence_privilege has_server_privilege has_table_privilege has_tablespace_privilege has_type_privilege hash_aclitem
- hash_array hash_numeric hash_range hashbeginscan hashbpchar hashbuild hashbuildempty hashbulkdelete hashchar hashcostestimate
- hashendscan hashenum hashfloat4 hashfloat8 hashgetbitmap hashgettuple hashinet
- hashinsert hashint2 hashint2vector hashint4 hashint8 hashmacaddr hashmarkpos
- hashname hashoid hashoidvector hashoptions hashrescan hashrestrpos hashtext
- hashvacuumcleanup hashvarlena height hmac host hostmask iclikejoinsel
- iclikesel icnlikejoinsel icnlikesel icregexeqjoinsel icregexeqsel icregexnejoinsel icregexnesel
- inet_client_addr inet_client_port inet_in inet_out inet_recv inet_send inet_server_addr
- inet_server_port inetand inetmi inetmi_int8 inetnot inetor inetpl
- int2 int24div int24eq int24ge int24gt int24le int24lt
- int24mi int24mul int24ne int24pl int28div int28eq int28ge
- int28gt int28le int28lt int28mi int28mul int28ne int28pl
- int2_accum int2_avg_accum int2_mul_cash int2_sum int2abs int2and int2div
- int2eq int2ge int2gt int2in int2larger int2le int2lt
- int2mi int2mod int2mul int2ne int2not int2or int2out
- int2pl int2recv int2send int2shl int2shr int2smaller int2um
- int2up int2vectoreq int2vectorin int2vectorout int2vectorrecv int2vectorsend int2xor
- int4 int42div int42eq int42ge int42gt int42le int42lt
- int42mi int42mul int42ne int42pl int48div int48eq int48ge
- int48gt int48le int48lt int48mi int48mul int48ne int48pl
- int4_accum int4_avg_accum int4_mul_cash int4_sum int4abs int4and int4div
- int4eq int4ge int4gt int4in int4inc int4larger int4le
- int4lt int4mi int4mod int4mul int4ne int4not int4or
- int4out int4pl int4range int4range_canonical int4range_subdiff int4recv int4send
- int4shl int4shr int4smaller int4um int4up int4xor int8
- int82div int82eq int82ge int82gt int82le int82lt int82mi
- int82mul int82ne int82pl int84div int84eq int84ge int84gt
- int84le int84lt int84mi int84mul int84ne int84pl int8_accum
- int8_avg int8_avg_accum int8_sum int8abs int8and int8div int8eq
- int8ge int8gt int8in int8inc int8inc_any int8inc_float8_float8 int8larger
- int8le int8lt int8mi int8mod int8mul int8ne int8not
- int8or int8out int8pl int8pl_inet int8range int8range_canonical int8range_subdiff
- int8recv int8send int8shl int8shr int8smaller int8um int8up
- int8xor integer_pl_date inter_lb inter_sb inter_sl internal_in internal_out
- interval_accum interval_avg interval_cmp interval_div interval_eq interval_ge interval_gt
- interval_hash interval_in interval_larger interval_le interval_lt interval_mi interval_mul
- interval_ne interval_out interval_pl interval_pl_date interval_pl_time interval_pl_timestamp interval_pl_timestamptz
- interval_pl_timetz interval_recv interval_send interval_smaller interval_transform interval_um intervaltypmodin
- intervaltypmodout intinterval isclosed isempty ishorizontal iso8859_1_to_utf8 iso8859_to_utf8
- iso_to_koi8r iso_to_mic iso_to_win1251 iso_to_win866 isopen isparallel isperp
- isvertical johab_to_utf8 json_array_elements jsonb_array_elements json_array_elements_text jsonb_array_elements_text
- json_array_length jsonb_array_length json_build_array json_build_object json_each jsonb_each json_each_text
- jsonb_each_text json_extract_path jsonb_extract_path json_extract_path_text jsonb_extract_path_text json_in json_object
- json_object_keys jsonb_object_keys json_out json_populate_record jsonb_populate_record json_populate_recordset jsonb_pretty
- jsonb_populate_recordset json_recv json_send jsonb_set json_typeof jsonb_typeof json_to_record jsonb_to_record json_to_recordset
- jsonb_to_recordset justify_interval koi8r_to_iso koi8r_to_mic koi8r_to_utf8 koi8r_to_win1251 koi8r_to_win866 koi8u_to_utf8
- lag language_handler_in language_handler_out last_value lastval latin1_to_mic latin2_to_mic latin2_to_win1250
- latin3_to_mic latin4_to_mic lead like_escape likejoinsel
- likesel line line_distance line_eq line_horizontal line_in line_interpt
- line_intersect line_out line_parallel line_perp line_recv line_send line_vertical
- ln lo_close lo_creat lo_create lo_export lo_import lo_lseek
- lo_open lo_tell lo_truncate lo_unlink log loread lower_inc
- lower_inf lowrite lseg lseg_center lseg_distance lseg_eq lseg_ge
- lseg_gt lseg_horizontal lseg_in lseg_interpt lseg_intersect lseg_le lseg_length
- lseg_lt lseg_ne lseg_out lseg_parallel lseg_perp lseg_recv lseg_send
- lseg_vertical macaddr_and macaddr_cmp macaddr_eq macaddr_ge macaddr_gt macaddr_in
- macaddr_le macaddr_lt macaddr_ne macaddr_not macaddr_or macaddr_out macaddr_recv
- macaddr_send makeaclitem masklen max mic_to_ascii mic_to_big5 mic_to_euc_cn
- mic_to_euc_jp mic_to_euc_kr mic_to_euc_tw mic_to_iso mic_to_koi8r mic_to_latin1 mic_to_latin2
- mic_to_latin3 mic_to_latin4 mic_to_sjis mic_to_win1250 mic_to_win1251 mic_to_win866 min
- mktinterval mod money mul_d_interval name nameeq namege
- namegt nameiclike nameicnlike nameicregexeq nameicregexne namein namele
- namelike namelt namene namenlike nameout namerecv nameregexeq
- nameregexne namesend neqjoinsel neqsel netmask network network_cmp
- network_eq network_ge network_gt network_le network_lt network_ne network_sub
- network_subeq network_sup network_supeq nextval nlikejoinsel nlikesel notlike
- npoints nth_value ntile numeric numeric_abs numeric_accum numeric_add
- numeric_avg numeric_avg_accum numeric_cmp numeric_div numeric_div_trunc numeric_eq numeric_exp
- numeric_fac numeric_ge numeric_gt numeric_in numeric_inc numeric_larger numeric_le
- numeric_ln numeric_log numeric_lt numeric_mod numeric_mul numeric_ne numeric_out
- numeric_power numeric_recv numeric_send numeric_smaller numeric_sqrt numeric_stddev_pop numeric_stddev_samp
- numeric_sub numeric_transform numeric_uminus numeric_uplus numeric_var_pop numeric_var_samp numerictypmodin
- numerictypmodout numnode numrange numrange_subdiff obj_description oid oideq
- oidge oidgt oidin oidlarger oidle oidlt oidne
- oidout oidrecv oidsend oidsmaller oidvectoreq oidvectorge oidvectorgt
- oidvectorin oidvectorle oidvectorlt oidvectorne oidvectorout oidvectorrecv oidvectorsend
- oidvectortypes on_pb on_pl on_ppath on_ps on_sb on_sl
- opaque_in opaque_out overlaps path path_add path_add_pt path_center
- path_contain_pt path_distance path_div_pt path_in path_inter path_length path_mul_pt
- path_n_eq path_n_ge path_n_gt path_n_le path_n_lt path_npoints path_out
- path_recv path_send path_sub_pt pclose percent_rank pg_advisory_lock pg_advisory_lock_shared
- pg_advisory_unlock pg_advisory_unlock_all pg_advisory_unlock_shared pg_advisory_xact_lock pg_advisory_xact_lock_shared
- pg_available_extension_versions pg_available_extensions pg_backend_pid pg_cancel_backend pg_char_to_encoding pg_collation_for
- pg_collation_is_visible pg_column_size pg_conf_load_time pg_conversion_is_visible pg_create_restore_point pg_current_xlog_insert_location
- pg_current_xlog_location pg_cursor pg_database_size pg_describe_object pg_encoding_max_length pg_encoding_to_char pg_export_snapshot
- pg_extension_config_dump pg_extension_update_paths pg_function_is_visible pg_get_constraintdef pg_get_expr pg_get_function_arguments
- pg_get_function_identity_arguments pg_get_function_result pg_get_functiondef pg_get_indexdef pg_get_keywords
- pg_get_ruledef pg_get_serial_sequence pg_get_triggerdef pg_get_userbyid pg_get_viewdef pg_has_role pg_indexes_size
- pg_is_in_recovery pg_is_other_temp_schema pg_is_xlog_replay_paused pg_last_xact_replay_timestamp pg_last_xlog_receive_location
- pg_last_xlog_replay_location pg_listening_channels pg_lock_status pg_ls_dir pg_my_temp_schema pg_node_tree_in pg_node_tree_out
- pg_node_tree_recv pg_node_tree_send pg_notify pg_opclass_is_visible pg_operator_is_visible pg_opfamily_is_visible pg_options_to_table
- pg_postmaster_start_time pg_prepared_statement pg_prepared_xact pg_read_binary_file pg_read_file pg_relation_filenode pg_relation_filepath
- pg_relation_size pg_reload_conf pg_rotate_logfile pg_sequence_parameters pg_show_all_settings pg_size_pretty pg_sleep pg_start_backup
- pg_stat_clear_snapshot pg_stat_file pg_stat_get_activity pg_stat_get_analyze_count pg_stat_get_autoanalyze_count pg_stat_get_autovacuum_count
- pg_stat_get_backend_activity pg_stat_get_backend_activity_start pg_stat_get_backend_client_addr pg_stat_get_backend_client_port
- pg_stat_get_backend_dbid pg_stat_get_backend_idset pg_stat_get_backend_pid pg_stat_get_backend_start pg_stat_get_backend_userid
- pg_stat_get_backend_waiting pg_stat_get_backend_xact_start pg_stat_get_bgwriter_buf_written_checkpoints pg_stat_get_bgwriter_buf_written_clean
- pg_stat_get_bgwriter_maxwritten_clean pg_stat_get_bgwriter_requested_checkpoints pg_stat_get_bgwriter_stat_reset_time
- pg_stat_get_bgwriter_timed_checkpoints pg_stat_get_blocks_fetched pg_stat_get_blocks_hit pg_stat_get_buf_alloc pg_stat_get_buf_fsync_backend
- pg_stat_get_buf_written_backend pg_stat_get_checkpoint_sync_time pg_stat_get_checkpoint_write_time pg_stat_get_db_blk_read_time
- pg_stat_get_db_blk_write_time pg_stat_get_db_blocks_fetched pg_stat_get_db_blocks_hit pg_stat_get_db_conflict_all pg_stat_get_db_conflict_bufferpin
- pg_stat_get_db_conflict_lock pg_stat_get_db_conflict_snapshot pg_stat_get_db_conflict_startup_deadlock pg_stat_get_db_conflict_tablespace
- pg_stat_get_db_deadlocks pg_stat_get_db_numbackends pg_stat_get_db_stat_reset_time pg_stat_get_db_temp_bytes pg_stat_get_db_temp_files
- pg_stat_get_db_tuples_deleted pg_stat_get_db_tuples_fetched pg_stat_get_db_tuples_inserted pg_stat_get_db_tuples_returned pg_stat_get_db_tuples_updated
- pg_stat_get_db_xact_commit pg_stat_get_db_xact_rollback pg_stat_get_dead_tuples pg_stat_get_function_calls pg_stat_get_function_self_time
- pg_stat_get_function_total_time pg_stat_get_last_analyze_time pg_stat_get_last_autoanalyze_time pg_stat_get_last_autovacuum_time
- pg_stat_get_last_vacuum_time pg_stat_get_live_tuples pg_stat_get_numscans pg_stat_get_tuples_deleted pg_stat_get_tuples_fetched
- pg_stat_get_tuples_hot_updated pg_stat_get_tuples_inserted pg_stat_get_tuples_returned pg_stat_get_tuples_updated pg_stat_get_vacuum_count
- pg_stat_get_wal_senders pg_stat_get_xact_blocks_fetched pg_stat_get_xact_blocks_hit pg_stat_get_xact_function_calls pg_stat_get_xact_function_self_time
- pg_stat_get_xact_function_total_time pg_stat_get_xact_numscans pg_stat_get_xact_tuples_deleted pg_stat_get_xact_tuples_fetched
- pg_stat_get_xact_tuples_hot_updated pg_stat_get_xact_tuples_inserted pg_stat_get_xact_tuples_returned pg_stat_get_xact_tuples_updated pg_stat_reset
- pg_stat_reset_shared pg_stat_reset_single_function_counters pg_stat_reset_single_table_counters pg_stop_backup pg_switch_xlog pg_table_is_visible
- pg_table_size pg_tablespace_databases pg_tablespace_location pg_tablespace_size pg_terminate_backend pg_timezone_abbrevs pg_timezone_names
- pg_total_relation_size pg_trigger_depth pg_try_advisory_lock pg_try_advisory_lock_shared pg_try_advisory_xact_lock pg_try_advisory_xact_lock_shared
- pg_ts_config_is_visible pg_ts_dict_is_visible pg_ts_parser_is_visible pg_ts_template_is_visible
- pg_type_is_visible pg_typeof pg_xact_commit_timestamp pg_last_committed_xact pg_xlog_location_diff pg_xlog_replay_pause pg_xlog_replay_resume pg_xlogfile_name pg_xlogfile_name_offset
- pgp_key_id pgp_pub_decrypt pgp_pub_decrypt_bytea pgp_pub_encrypt pgp_pub_encrypt_bytea pgp_sym_decrypt pgp_sym_decrypt_bytea
- pgp_sym_encrypt pgp_sym_encrypt_bytea pi plainto_tsquery plpgsql_call_handler plpgsql_inline_handler plpgsql_validator
- point point_above point_add point_below point_distance point_div point_eq
- point_horiz point_in point_left point_mul point_ne point_out point_recv
- point_right point_send point_sub point_vert poly_above poly_below poly_center
- poly_contain poly_contain_pt poly_contained poly_distance poly_in poly_left poly_npoints
- poly_out poly_overabove poly_overbelow poly_overlap poly_overleft poly_overright poly_recv
- poly_right poly_same poly_send polygon popen positionjoinsel positionsel
- postgresql_fdw_validator pow power prsd_end prsd_headline prsd_lextype prsd_nexttoken
- prsd_start pt_contained_circle pt_contained_poly querytree
- quote_nullable radians radius random range_adjacent range_after range_before
- range_cmp range_contained_by range_contains range_contains_elem range_eq range_ge range_gist_compress
- range_gist_consistent range_gist_decompress range_gist_penalty range_gist_picksplit range_gist_same range_gist_union range_gt
- range_in range_intersect range_le range_lt range_minus range_ne range_out
- range_overlaps range_overleft range_overright range_recv range_send range_typanalyze range_union
- rank record_eq record_ge record_gt record_in record_le record_lt
- record_ne record_out record_recv record_send regclass regclassin regclassout
- regclassrecv regclasssend regconfigin regconfigout regconfigrecv regconfigsend regdictionaryin
- regdictionaryout regdictionaryrecv regdictionarysend regexeqjoinsel regexeqsel regexnejoinsel regexnesel
- regexp_matches regexp_replace regexp_split_to_array regexp_split_to_table regoperatorin regoperatorout regoperatorrecv
- regoperatorsend regoperin regoperout regoperrecv regopersend regprocedurein regprocedureout
- regprocedurerecv regproceduresend regprocin regprocout regprocrecv regprocsend regr_avgx
- regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy
- regr_syy regtypein regtypeout regtyperecv regtypesend reltime reltimeeq
- reltimege reltimegt reltimein reltimele reltimelt reltimene reltimeout
- reltimerecv reltimesend reverse round row_number row_to_json
- scalargtjoinsel scalargtsel scalarltjoinsel scalarltsel
- session_user set_config set_masklen setseed setval setweight shell_in
- shell_out shift_jis_2004_to_euc_jis_2004 shift_jis_2004_to_utf8 shobj_description sign similar_escape sin
- sjis_to_euc_jp sjis_to_mic sjis_to_utf8 slope smgreq smgrin smgrne
- smgrout spg_kd_choose spg_kd_config spg_kd_inner_consistent spg_kd_picksplit spg_quad_choose spg_quad_config
- spg_quad_inner_consistent spg_quad_leaf_consistent spg_quad_picksplit spg_text_choose spg_text_config spg_text_inner_consistent spg_text_leaf_consistent
- spg_text_picksplit spgbeginscan spgbuild spgbuildempty spgbulkdelete spgcanreturn spgcostestimate
- spgendscan spggetbitmap spggettuple spginsert spgmarkpos spgoptions spgrescan
- spgrestrpos spgvacuumcleanup sqrt statement_timestamp stddev stddev_pop stddev_samp
- string_agg string_agg_finalfn string_agg_transfn string_to_array strip sum
- tan text text_ge text_gt text_larger
- text_le text_lt text_pattern_ge text_pattern_gt text_pattern_le text_pattern_lt text_smaller
- textanycat textcat texteq texticlike texticnlike texticregexeq texticregexne
- textin textlen textlike textne textnlike textout textrecv
- textregexeq textregexne textsend thesaurus_init thesaurus_lexize tideq tidge
- tidgt tidin tidlarger tidle tidlt tidne tidout
- tidrecv tidsend tidsmaller time time_cmp time_eq time_ge
- time_gt time_hash time_in time_larger time_le time_lt time_mi_interval
- time_mi_time time_ne time_out time_pl_interval time_recv time_send time_smaller
- time_transform timedate_pl timemi timenow timepl timestamp timestamp_cmp
- timestamp_cmp_date timestamp_cmp_timestamptz timestamp_eq timestamp_eq_date timestamp_eq_timestamptz timestamp_ge timestamp_ge_date
- timestamp_ge_timestamptz timestamp_gt timestamp_gt_date timestamp_gt_timestamptz timestamp_hash timestamp_in timestamp_larger
- timestamp_le timestamp_le_date timestamp_le_timestamptz timestamp_lt timestamp_lt_date timestamp_lt_timestamptz timestamp_mi
- timestamp_mi_interval timestamp_ne timestamp_ne_date timestamp_ne_timestamptz timestamp_out timestamp_pl_interval timestamp_recv
- timestamp_send timestamp_smaller timestamp_sortsupport timestamp_transform timestamptypmodin timestamptypmodout timestamptz
- timestamptz_cmp timestamptz_cmp_date timestamptz_cmp_timestamp timestamptz_eq timestamptz_eq_date timestamptz_eq_timestamp timestamptz_ge
- timestamptz_ge_date timestamptz_ge_timestamp timestamptz_gt timestamptz_gt_date timestamptz_gt_timestamp timestamptz_in timestamptz_larger
- timestamptz_le timestamptz_le_date timestamptz_le_timestamp timestamptz_lt timestamptz_lt_date timestamptz_lt_timestamp timestamptz_mi
- timestamptz_mi_interval timestamptz_ne timestamptz_ne_date timestamptz_ne_timestamp timestamptz_out timestamptz_pl_interval timestamptz_recv
- timestamptz_send timestamptz_smaller timestamptztypmodin timestamptztypmodout timetypmodin timetypmodout timetz
- timetz_cmp timetz_eq timetz_ge timetz_gt timetz_hash timetz_in timetz_larger
- timetz_le timetz_lt timetz_mi_interval timetz_ne timetz_out timetz_pl_interval timetz_recv
- timetz_send timetz_smaller timetzdate_pl timetztypmodin timetztypmodout timezone tinterval
- tintervalct tintervalend tintervaleq tintervalge tintervalgt tintervalin tintervalle
- tintervalleneq tintervallenge tintervallengt tintervallenle tintervallenlt tintervallenne tintervallt
- tintervalne tintervalout tintervalov tintervalrecv tintervalrel tintervalsame tintervalsend
- tintervalstart to_json to_tsquery to_tsvector transaction_timestamp trigger_out trunc ts_debug
- ts_headline ts_lexize ts_match_qv ts_match_tq ts_match_tt ts_match_vq ts_parse
- ts_rank ts_rank_cd ts_rewrite ts_stat ts_token_type ts_typanalyze tsmatchjoinsel
- tsmatchsel tsq_mcontained tsq_mcontains tsquery_and tsquery_cmp tsquery_eq tsquery_ge
- tsquery_gt tsquery_le tsquery_lt tsquery_ne tsquery_not tsquery_or tsqueryin
- tsqueryout tsqueryrecv tsquerysend tsrange tsrange_subdiff tstzrange tstzrange_subdiff
- tsvector_cmp tsvector_concat tsvector_eq tsvector_ge tsvector_gt tsvector_le tsvector_lt
- tsvector_ne tsvectorin tsvectorout tsvectorrecv tsvectorsend txid_current txid_current_snapshot
- txid_snapshot_in txid_snapshot_out txid_snapshot_recv txid_snapshot_send txid_snapshot_xip txid_snapshot_xmax txid_snapshot_xmin
- txid_visible_in_snapshot uhc_to_utf8 unknownin unknownout unknownrecv unknownsend unnest
- upper_inc upper_inf utf8_to_ascii utf8_to_big5 utf8_to_euc_cn utf8_to_euc_jis_2004 utf8_to_euc_jp
- utf8_to_euc_kr utf8_to_euc_tw utf8_to_gb18030 utf8_to_gbk utf8_to_iso8859 utf8_to_iso8859_1 utf8_to_johab
- utf8_to_koi8r utf8_to_koi8u utf8_to_shift_jis_2004 utf8_to_sjis utf8_to_uhc utf8_to_win uuid_cmp
- uuid_eq uuid_ge uuid_gt uuid_hash uuid_in uuid_le uuid_lt
- uuid_ne uuid_out uuid_recv uuid_send var_pop var_samp varbit
- varbit_in varbit_out varbit_recv varbit_send varbit_transform varbitcmp varbiteq
- varbitge varbitgt varbitle varbitlt varbitne varbittypmodin varbittypmodout
- varchar varchar_transform varcharin varcharout varcharrecv varcharsend varchartypmodin
- varchartypmodout variance version void_in void_out void_recv void_send
- width width_bucket win1250_to_latin2 win1250_to_mic win1251_to_iso win1251_to_koi8r win1251_to_mic
- win1251_to_win866 win866_to_iso win866_to_koi8r win866_to_mic win866_to_win1251 win_to_utf8 xideq
- xideqint4 xidin xidout xidrecv xidsend xml xml_in xmlcomment xpath xpath_exists table_to_xmlschema
- query_to_xmlschema cursor_to_xmlschema table_to_xml_and_xmlschema query_to_xml_and_xmlschema
- schema_to_xml schema_to_xmlschema schema_to_xml_and_xmlschema database_to_xml database_to_xmlschema xmlroot
- database_to_xml_and_xmlschema table_to_xml query_to_xmlcursor_to_xml xmlcomment xmlconcat xmlelement xmlforest
- xml_is_well_formed_content xml_is_well_formed_document xml_is_well_formed xml_out xml_recv xml_send xmlagg xmlpi
- );
+ ascii age bit_length btrim cardinality cast char_length character_length coalesce
+ convert chr current_date current_time current_timestamp count decode date_part date_trunc
+ encode extract get_byte get_bit initcap isfinite interval justify_hours justify_days
+ lower length lpad ltrim localtime localtimestamp md5 now octet_length overlay position pg_client_encoding
+ quote_ident quote_literal repeat replace rpad rtrim substring split_part strpos substr set_byte set_bit
+ trim to_ascii to_hex translate to_char to_date to_timestamp to_number timeofday upper
+ abbrev abs abstime abstimeeq abstimege abstimegt abstimein abstimele
+ abstimelt abstimene abstimeout abstimerecv abstimesend aclcontains acldefault
+ aclexplode aclinsert aclitemeq aclitemin aclitemout aclremove acos
+ any_in any_out anyarray_in anyarray_out anyarray_recv anyarray_send anyelement_in
+ anyelement_out anyenum_in anyenum_out anynonarray_in anynonarray_out anyrange_in anyrange_out
+ anytextcat area areajoinsel areasel armor array_agg array_agg_finalfn
+ array_agg_transfn array_append array_cat array_dims array_eq array_fill array_ge array_positions
+ array_gt array_in array_larger array_le array_length array_lower array_lt array_position
+ array_ndims array_ne array_out array_prepend array_recv array_remove array_replace array_send array_smaller
+ array_to_json array_to_string array_typanalyze array_upper arraycontained arraycontains arraycontjoinsel
+ arraycontsel arrayoverlap ascii_to_mic ascii_to_utf8 asin atan atan2
+ avg big5_to_euc_tw big5_to_mic big5_to_utf8 bit bit_and bit_in
+ bit_or bit_out bit_recv bit_send bitand bitcat bitcmp
+ biteq bitge bitgt bitle bitlt bitne bitnot
+ bitor bitshiftleft bitshiftright bittypmodin bittypmodout bitxor bool
+ bool_and bool_or booland_statefunc booleq boolge boolgt boolin
+ boolle boollt boolne boolor_statefunc boolout boolrecv boolsend
+ box box_above box_above_eq box_add box_below box_below_eq box_center
+ box_contain box_contain_pt box_contained box_distance box_div box_eq box_ge
+ box_gt box_in box_intersect box_le box_left box_lt box_mul
+ box_out box_overabove box_overbelow box_overlap box_overleft box_overright box_recv
+ box_right box_same box_send box_sub bpchar bpchar_larger bpchar_pattern_ge
+ bpchar_pattern_gt bpchar_pattern_le bpchar_pattern_lt bpchar_smaller bpcharcmp bpchareq bpcharge
+ bpchargt bpchariclike bpcharicnlike bpcharicregexeq bpcharicregexne bpcharin bpcharle
+ bpcharlike bpcharlt bpcharne bpcharnlike bpcharout bpcharrecv bpcharregexeq
+ bpcharregexne bpcharsend bpchartypmodin bpchartypmodout broadcast btabstimecmp btarraycmp
+ btbeginscan btboolcmp btbpchar_pattern_cmp btbuild btbuildempty btbulkdelete btcanreturn
+ btcharcmp btcostestimate btendscan btfloat48cmp btfloat4cmp btfloat4sortsupport btfloat84cmp
+ btfloat8cmp btfloat8sortsupport btgetbitmap btgettuple btinsert btint24cmp btint28cmp
+ btint2cmp btint2sortsupport btint42cmp btint48cmp btint4cmp btint4sortsupport btint82cmp
+ btint84cmp btint8cmp btint8sortsupport btmarkpos btnamecmp btnamesortsupport btoidcmp
+ btoidsortsupport btoidvectorcmp btoptions btrecordcmp btreltimecmp btrescan btrestrpos
+ bttext_pattern_cmp bttextcmp bttidcmp bttintervalcmp btvacuumcleanup bytea_string_agg_finalfn
+ bytea_string_agg_transfn byteacat byteacmp byteaeq byteage byteagt byteain byteale
+ bytealike bytealt byteane byteanlike byteaout bytearecv byteasend
+ cash_cmp cash_div_cash cash_div_flt4 cash_div_flt8 cash_div_int2 cash_div_int4 cash_eq
+ cash_ge cash_gt cash_in cash_le cash_lt cash_mi cash_mul_flt4
+ cash_mul_flt8 cash_mul_int2 cash_mul_int4 cash_ne cash_out cash_pl cash_recv
+ cash_send cash_words cashlarger cashsmaller cbrt ceil ceiling
+ center char chareq charge chargt charin charle
+ charlt charne charout charrecv charsend cideq cidin
+ cidout cidr cidr_in cidr_out cidr_recv cidr_send cidrecv
+ cidsend circle circle_above circle_add_pt circle_below circle_center circle_contain
+ circle_contain_pt circle_contained circle_distance circle_div_pt circle_eq circle_ge circle_gt
+ circle_in circle_le circle_left circle_lt circle_mul_pt circle_ne circle_out
+ circle_overabove circle_overbelow circle_overlap circle_overleft circle_overright circle_recv circle_right
+ circle_same circle_send circle_sub_pt clock_timestamp close_lb close_ls close_lseg
+ close_pb close_pl close_ps close_sb close_sl col_description concat
+ concat_ws contjoinsel contsel convert_from convert_to corr cos
+ cot covar_pop covar_samp crypt cstring_in cstring_out cstring_recv
+ cstring_send cume_dist current_database current_query current_schema current_schemas current_setting
+ current_user currtid currtid2 currval date date_cmp date_cmp_timestamp date_cmp_timestamptz date_eq
+ date_eq_timestamp date_eq_timestamptz date_ge date_ge_timestamp date_ge_timestamptz date_gt date_gt_timestamp
+ date_gt_timestamptz date_in date_larger date_le date_le_timestamp date_le_timestamptz date_lt
+ date_lt_timestamp date_lt_timestamptz date_mi date_mi_interval date_mii date_ne date_ne_timestamp
+ date_ne_timestamptz date_out date_pl_interval date_pli date_recv date_send date_smaller
+ date_sortsupport daterange daterange_canonical daterange_subdiff datetime_pl datetimetz_pl
+ dblink_connect_u dblink_connect dblink_disconnect dblink_exec dblink_open dblink_fetch dblink_close
+ dblink_get_connections dblink_error_message dblink_send_query dblink_is_busy dblink_get_notify
+ dblink_get_result dblink_cancel_query dblink_get_pkey dblink_build_sql_insert dblink_build_sql_delete
+ dblink_build_sql_update dblink dcbrt dearmor decrypt decrypt_iv degrees dense_rank dexp diagonal
+ decimal diameter digest dispell_init dispell_lexize dist_cpoly dist_lb dist_pb
+ dist_pc dist_pl dist_ppath dist_ps dist_sb dist_sl div
+ dlog1 dlog10 domain_in domain_recv dpow dround dsimple_init
+ dsimple_lexize dsnowball_init dsnowball_lexize dsqrt dsynonym_init dsynonym_lexize dtrunc
+ elem_contained_by_range encrypt encrypt_iv enum_cmp enum_eq enum_first enum_ge
+ enum_gt enum_in enum_larger enum_last enum_le enum_lt enum_ne
+ enum_out enum_range enum_recv enum_send enum_smaller eqjoinsel eqsel
+ euc_cn_to_mic euc_cn_to_utf8 euc_jis_2004_to_shift_jis_2004 euc_jis_2004_to_utf8
+ euc_jp_to_mic euc_jp_to_sjis euc_jp_to_utf8
+ euc_kr_to_mic euc_kr_to_utf8 euc_tw_to_big5 euc_tw_to_mic euc_tw_to_utf8 every exp
+ factorial family fdw_handler_in fdw_handler_out first_value float4 float48div
+ float48eq float48ge float48gt float48le float48lt float48mi float48mul
+ float48ne float48pl float4_accum float4abs float4div float4eq float4ge
+ float4gt float4in float4larger float4le float4lt float4mi float4mul
+ float4ne float4out float4pl float4recv float4send float4smaller float4um
+ float4up float8 float84div float84eq float84ge float84gt float84le
+ float84lt float84mi float84mul float84ne float84pl float8_accum float8_avg
+ float8_combine float8_regr_combine float8_corr float8_covar_pop float8_covar_samp
+ float8_regr_accum float8_regr_avgx float8_regr_avgy float8_regr_intercept
+ float8_regr_r2 float8_regr_slope float8_regr_sxx float8_regr_sxy float8_regr_syy
+ float8_stddev_pop float8_stddev_samp
+ float8_var_pop float8_var_samp float8abs float8div float8eq float8ge float8gt
+ float8in float8larger float8le float8lt float8mi float8mul float8ne
+ float8out float8pl float8recv float8send float8smaller float8um float8up
+ floor flt4_mul_cash flt8_mul_cash fmgr_c_validator fmgr_internal_validator fmgr_sql_validator format
+ format_type gb18030_to_utf8 gbk_to_utf8 gen_random_bytes gen_salt generate_series generate_subscripts
+ get_current_ts_config getdatabaseencoding getpgusername gin_cmp_prefix gin_cmp_tslexeme gin_extract_tsquery gin_extract_tsvector
+ gin_tsquery_consistent ginarrayconsistent ginarrayextract ginbeginscan ginbuild ginbuildempty ginbulkdelete
+ gincostestimate ginendscan gingetbitmap gininsert ginmarkpos ginoptions ginqueryarrayextract
+ ginrescan ginrestrpos ginvacuumcleanup gist_box_compress gist_box_consistent gist_box_decompress gist_box_penalty
+ gist_box_picksplit gist_box_same gist_box_union gist_circle_compress gist_circle_consistent gist_point_compress gist_point_consistent
+ gist_point_distance gist_poly_compress gist_poly_consistent gistbeginscan gistbuild gistbuildempty gistbulkdelete
+ gistcostestimate gistendscan gistgetbitmap gistgettuple gistinsert gistmarkpos gistoptions
+ gistrescan gistrestrpos gistvacuumcleanup gtsquery_compress gtsquery_consistent gtsquery_decompress gtsquery_penalty
+ gtsquery_picksplit gtsquery_same gtsquery_union gtsvector_compress gtsvector_consistent gtsvector_decompress gtsvector_penalty
+ gtsvector_picksplit gtsvector_same gtsvector_union gtsvectorin gtsvectorout has_any_column_privilege has_column_privilege
+ has_database_privilege has_foreign_data_wrapper_privilege has_function_privilege has_language_privilege
+ has_schema_privilege has_sequence_privilege has_server_privilege has_table_privilege has_tablespace_privilege
+ has_type_privilege hash_aclitem hash_array hash_numeric hash_range hashbeginscan hashbpchar hashbuild
+ hashbuildempty hashbulkdelete hashchar hashcostestimate hash_aclitem_extended
+ hashendscan hashenum hashfloat4 hashfloat8 hashgetbitmap hashgettuple hashinet hashinsert hashint2
+ hashint2extended hashint2vector hashint4 hashint4extended hashint8 hashint8extended hashmacaddr
+ hashfloat4extended hashfloat8extended hashcharextended hashoidextended hashnameextended hashmarkpos
+ hashoidvectorextended hashmacaddrextended hashinetextended hashname hashoid hashoidvector hashoptions
+ hash_numeric_extended hashmacaddr8extended hash_array_extended hashrescan hashrestrpos hashtext
+ hashbpcharextended time_hash_extended timetz_hash_extended interval_hash_extended timestamp_hash_extended
+ uuid_hash_extended pg_lsn_hash_extended hashenumextended jsonb_hash_extended hash_range_extended
+ hashtextextended hashvacuumcleanup hashvarlena height hmac host hostmask iclikejoinsel
+ iclikesel icnlikejoinsel icnlikesel icregexeqjoinsel icregexeqsel icregexnejoinsel icregexnesel
+ inet_client_addr inet_client_port inet_in inet_out inet_recv inet_send inet_server_addr
+ inet_server_port inetand inetmi inetmi_int8 inetnot inetor inetpl
+ int int2 int24div int24eq int24ge int24gt int24le int24lt integer
+ int24mi int24mul int24ne int24pl int28div int28eq int28ge
+ int28gt int28le int28lt int28mi int28mul int28ne int28pl
+ int2_accum int2_avg_accum int2_mul_cash int2_sum int2abs int2and int2div
+ int2eq int2ge int2gt int2in int2larger int2le int2lt
+ int2mi int2mod int2mul int2ne int2not int2or int2out
+ int2pl int2recv int2send int2shl int2shr int2smaller int2um
+ int2up int2vectoreq int2vectorin int2vectorout int2vectorrecv int2vectorsend int2xor
+ int4 int42div int42eq int42ge int42gt int42le int42lt
+ int42mi int42mul int42ne int42pl int48div int48eq int48ge
+ int48gt int48le int48lt int48mi int48mul int48ne int48pl
+ int4_accum int4_avg_accum int4_mul_cash int4_sum int4abs int4and int4div
+ int4eq int4ge int4gt int4in int4inc int4larger int4le
+ int4lt int4mi int4mod int4mul int4ne int4not int4or
+ int4out int4pl int4range int4range_canonical int4range_subdiff int4recv int4send
+ int4shl int4shr int4smaller int4um int4up int4xor int8
+ int82div int82eq int82ge int82gt int82le int82lt int82mi
+ int82mul int82ne int82pl int84div int84eq int84ge int84gt
+ int84le int84lt int84mi int84mul int84ne int84pl int8_accum
+ int8_avg int8_avg_accum int8_sum int8abs int8and int8div int8eq
+ int8ge int8gt int8in int8inc int8inc_any int8inc_float8_float8 int8larger
+ int8le int8lt int8mi int8mod int8mul int8ne int8not
+ int8or int8out int8pl int8pl_inet int8range int8range_canonical int8range_subdiff
+ int8recv int8send int8shl int8shr int8smaller int8um int8up
+ int8xor integer_pl_date inter_lb inter_sb inter_sl internal_in internal_out
+ interval_accum interval_avg interval_cmp interval_div interval_eq interval_ge interval_gt
+ interval_hash interval_in interval_larger interval_le interval_lt interval_mi interval_mul
+ interval_ne interval_out interval_pl interval_pl_date interval_pl_time interval_pl_timestamp interval_pl_timestamptz
+ interval_pl_timetz interval_recv interval_send interval_smaller interval_transform interval_um intervaltypmodin
+ intervaltypmodout intinterval isclosed isempty ishorizontal iso8859_1_to_utf8 iso8859_to_utf8
+ iso_to_koi8r iso_to_mic iso_to_win1251 iso_to_win866 isopen isparallel isperp
+ isvertical johab_to_utf8 json_agg jsonb_agg json_array_elements jsonb_array_elements json_array_elements_text jsonb_array_elements_text
+ json_array_length jsonb_array_length json_build_array json_build_object json_each jsonb_each json_each_text
+ jsonb_each_text json_extract_path jsonb_extract_path json_extract_path_text jsonb_extract_path_text json_in
+ json_object json_object_agg jsonb_object_agg json_object_keys jsonb_object_keys json_out json_populate_record
+ jsonb_populate_record json_populate_recordset jsonb_pretty jsonb_populate_recordset json_recv json_send
+ jsonb_set json_typeof jsonb_typeof json_to_record jsonb_to_record json_to_recordset jsonb_to_recordset
+ justify_interval koi8r_to_iso koi8r_to_mic koi8r_to_utf8 koi8r_to_win1251 koi8r_to_win866 koi8u_to_utf8
+ jsonb_path_query jsonb_build_object
+ lag language_handler_in language_handler_out last_value lastval latin1_to_mic latin2_to_mic latin2_to_win1250
+ latin3_to_mic latin4_to_mic lead like_escape likejoinsel
+ likesel line line_distance line_eq line_horizontal line_in line_interpt
+ line_intersect line_out line_parallel line_perp line_recv line_send line_vertical
+ ln lo_close lo_creat lo_create lo_export lo_import lo_lseek
+ lo_open lo_tell lo_truncate lo_unlink log loread lower_inc
+ lower_inf lowrite lseg lseg_center lseg_distance lseg_eq lseg_ge
+ lseg_gt lseg_horizontal lseg_in lseg_interpt lseg_intersect lseg_le lseg_length
+ lseg_lt lseg_ne lseg_out lseg_parallel lseg_perp lseg_recv lseg_send
+ lseg_vertical macaddr_and macaddr_cmp macaddr_eq macaddr_ge macaddr_gt macaddr_in
+ macaddr_le macaddr_lt macaddr_ne macaddr_not macaddr_or macaddr_out macaddr_recv
+ macaddr_send makeaclitem make_interval make_tsrange masklen max mic_to_ascii mic_to_big5 mic_to_euc_cn
+ mic_to_euc_jp mic_to_euc_kr mic_to_euc_tw mic_to_iso mic_to_koi8r mic_to_latin1 mic_to_latin2
+ mic_to_latin3 mic_to_latin4 mic_to_sjis mic_to_win1250 mic_to_win1251 mic_to_win866 min
+ mktinterval mode mod money mul_d_interval name nameeq namege
+ namegt nameiclike nameicnlike nameicregexeq nameicregexne namein namele
+ namelike namelt namene namenlike nameout namerecv nameregexeq
+ nameregexne namesend neqjoinsel neqsel netmask network network_cmp
+ network_eq network_ge network_gt network_le network_lt network_ne network_sub
+ network_subeq network_sup network_supeq nextval nlikejoinsel nlikesel notlike
+ npoints nth_value ntile numeric numeric_abs numeric_accum numeric_add
+ numeric_avg numeric_avg_accum numeric_cmp numeric_div numeric_div_trunc numeric_eq numeric_exp
+ numeric_fac numeric_ge numeric_gt numeric_in numeric_inc numeric_larger numeric_le
+ numeric_ln numeric_log numeric_lt numeric_mod numeric_mul numeric_ne numeric_out
+ numeric_power numeric_recv numeric_send numeric_smaller numeric_sqrt numeric_stddev_pop numeric_stddev_samp
+ numeric_sub numeric_transform numeric_uminus numeric_uplus numeric_var_pop numeric_var_samp numerictypmodin
+ numerictypmodout numnode numrange numrange_subdiff obj_description oid oideq
+ oidge oidgt oidin oidlarger oidle oidlt oidne
+ oidout oidrecv oidsend oidsmaller oidvectoreq oidvectorge oidvectorgt
+ oidvectorin oidvectorle oidvectorlt oidvectorne oidvectorout oidvectorrecv oidvectorsend
+ oidvectortypes on_pb on_pl on_ppath on_ps on_sb on_sl
+ opaque_in opaque_out overlaps path path_add path_add_pt path_center
+ path_contain_pt path_distance path_div_pt path_in path_inter path_length path_mul_pt
+ path_n_eq path_n_ge path_n_gt path_n_le path_n_lt path_npoints path_out
+ path_recv path_send path_sub_pt pclose percent_rank percentile_cont percentile_disc
+ pg_advisory_lock pg_advisory_lock_shared pg_advisory_unlock pg_advisory_unlock_all pg_advisory_unlock_shared
+ pg_advisory_xact_lock pg_advisory_xact_lock_shared pg_available_extension_versions pg_available_extensions
+ pg_backend_pid pg_cancel_backend pg_char_to_encoding pg_collation_for pg_collation_is_visible pg_column_size
+ pg_conf_load_time pg_conversion_is_visible pg_create_restore_point pg_current_xlog_insert_location
+ pg_current_xlog_location pg_cursor pg_database_size pg_describe_object pg_encoding_max_length
+ pg_encoding_to_char pg_export_snapshot pg_extension_config_dump pg_extension_update_paths pg_function_is_visible
+ pg_get_constraintdef pg_get_expr pg_get_function_arguments pg_filenode_relation pg_indexam_has_property
+ pg_get_function_identity_arguments pg_get_function_result pg_get_functiondef pg_get_indexdef pg_get_keywords
+ pg_get_ruledef pg_get_serial_sequence pg_get_triggerdef pg_get_userbyid pg_get_viewdef pg_has_role
+ pg_indexes_size pg_is_in_recovery pg_is_other_temp_schema pg_is_xlog_replay_paused pg_last_xact_replay_timestamp
+ pg_last_xlog_receive_location pg_last_xlog_replay_location pg_listening_channels pg_lock_status pg_ls_dir
+ pg_my_temp_schema pg_node_tree_in pg_node_tree_out pg_node_tree_recv pg_node_tree_send pg_notify
+ pg_opclass_is_visible pg_operator_is_visible pg_opfamily_is_visible pg_options_to_table pg_index_has_property
+ pg_postmaster_start_time pg_prepared_statement pg_prepared_xact pg_read_binary_file pg_read_file
+ pg_relation_filenode pg_relation_filepath pg_relation_size pg_reload_conf pg_rotate_logfile
+ pg_sequence_parameters pg_show_all_settings pg_size_pretty pg_sleep pg_start_backup pg_index_column_has_property
+ pg_stat_clear_snapshot pg_stat_file pg_stat_get_activity pg_stat_get_analyze_count pg_stat_get_autoanalyze_count
+ pg_stat_get_autovacuum_count pg_get_object_address pg_identify_object_as_address pg_stat_get_backend_activity
+ pg_stat_get_backend_activity_start pg_stat_get_backend_client_addr pg_stat_get_backend_client_port
+ pg_stat_get_backend_dbid pg_stat_get_backend_idset pg_stat_get_backend_pid pg_stat_get_backend_start
+ pg_stat_get_backend_userid pg_stat_get_backend_waiting pg_stat_get_backend_xact_start
+ pg_stat_get_bgwriter_buf_written_checkpoints pg_stat_get_bgwriter_buf_written_clean
+ pg_stat_get_bgwriter_maxwritten_clean pg_stat_get_bgwriter_requested_checkpoints
+ pg_stat_get_bgwriter_stat_reset_time pg_stat_get_bgwriter_timed_checkpoints pg_stat_get_blocks_fetched
+ pg_stat_get_blocks_hit pg_stat_get_buf_alloc pg_stat_get_buf_fsync_backend pg_stat_get_buf_written_backend
+ pg_stat_get_checkpoint_sync_time pg_stat_get_checkpoint_write_time pg_stat_get_db_blk_read_time
+ pg_stat_get_db_blk_write_time pg_stat_get_db_blocks_fetched pg_stat_get_db_blocks_hit
+ pg_stat_get_db_conflict_all pg_stat_get_db_conflict_bufferpin pg_stat_get_db_conflict_lock
+ pg_stat_get_db_conflict_snapshot pg_stat_get_db_conflict_startup_deadlock pg_stat_get_db_conflict_tablespace
+ pg_stat_get_db_deadlocks pg_stat_get_db_numbackends pg_stat_get_db_stat_reset_time pg_stat_get_db_temp_bytes
+ pg_stat_get_db_temp_files pg_stat_get_db_tuples_deleted pg_stat_get_db_tuples_fetched
+ pg_stat_get_db_tuples_inserted pg_stat_get_db_tuples_returned pg_stat_get_db_tuples_updated
+ pg_stat_get_db_xact_commit pg_stat_get_db_xact_rollback pg_stat_get_dead_tuples pg_stat_get_function_calls
+ pg_stat_get_function_self_time pg_stat_get_function_total_time pg_stat_get_last_analyze_time
+ pg_stat_get_last_autoanalyze_time pg_stat_get_last_autovacuum_time pg_stat_get_last_vacuum_time
+ pg_stat_get_live_tuples pg_stat_get_numscans pg_stat_get_tuples_deleted pg_stat_get_tuples_fetched
+ pg_stat_get_tuples_hot_updated pg_stat_get_tuples_inserted pg_stat_get_tuples_returned
+ pg_stat_get_tuples_updated pg_stat_get_vacuum_count pg_stat_get_wal_senders pg_stat_get_xact_blocks_fetched
+ pg_stat_get_xact_blocks_hit pg_stat_get_xact_function_calls pg_stat_get_xact_function_self_time
+ pg_stat_get_xact_function_total_time pg_stat_get_xact_numscans pg_stat_get_xact_tuples_deleted
+ pg_stat_get_xact_tuples_fetched pg_stat_get_xact_tuples_hot_updated pg_stat_get_xact_tuples_inserted
+ pg_stat_get_xact_tuples_returned pg_stat_get_xact_tuples_updated pg_stat_reset pg_stat_reset_shared
+ pg_stat_reset_single_function_counters pg_stat_reset_single_table_counters pg_stop_backup pg_switch_xlog
+ pg_table_is_visible pg_table_size pg_tablespace_databases pg_tablespace_location pg_tablespace_size
+ pg_terminate_backend pg_timezone_abbrevs pg_timezone_names pg_total_relation_size pg_trigger_depth
+ pg_try_advisory_lock pg_try_advisory_lock_shared pg_try_advisory_xact_lock pg_try_advisory_xact_lock_shared
+ pg_ts_config_is_visible pg_ts_dict_is_visible pg_ts_parser_is_visible pg_ts_template_is_visible
+ pg_type_is_visible pg_typeof pg_xact_commit_timestamp pg_last_committed_xact pg_xlog_location_diff
+ pg_xlog_replay_pause pg_xlog_replay_resume pg_xlogfile_name pg_xlogfile_name_offset pgp_key_id pgp_pub_decrypt
+ pgp_pub_decrypt_bytea pgp_pub_encrypt pgp_pub_encrypt_bytea pgp_sym_decrypt pgp_sym_decrypt_bytea
+ pgp_sym_encrypt pgp_sym_encrypt_bytea pi plainto_tsquery plpgsql_call_handler plpgsql_inline_handler
+ plpgsql_validator point point_above point_add point_below point_distance point_div point_eq
+ point_horiz point_in point_left point_mul point_ne point_out point_recv
+ point_right point_send point_sub point_vert poly_above poly_below poly_center
+ poly_contain poly_contain_pt poly_contained poly_distance poly_in poly_left poly_npoints
+ poly_out poly_overabove poly_overbelow poly_overlap poly_overleft poly_overright poly_recv
+ poly_right poly_same poly_send polygon popen positionjoinsel positionsel
+ postgresql_fdw_validator pow power prsd_end prsd_headline prsd_lextype prsd_nexttoken
+ prsd_start pt_contained_circle pt_contained_poly querytree
+ quote_nullable radians radius random range_adjacent range_after range_before
+ range_cmp range_contained_by range_contains range_contains_elem range_eq range_ge range_gist_compress
+ range_gist_consistent range_gist_decompress range_gist_penalty range_gist_picksplit range_gist_same range_gist_union range_gt
+ range_in range_intersect range_le range_lt range_minus range_ne range_out
+ range_overlaps range_overleft range_overright range_recv range_send range_typanalyze range_union
+ rank record_eq record_ge record_gt record_in record_le record_lt
+ record_ne record_out record_recv record_send regclass regclassin regclassout
+ regclassrecv regclasssend regconfigin regconfigout regconfigrecv regconfigsend regdictionaryin
+ regdictionaryout regdictionaryrecv regdictionarysend regexeqjoinsel regexeqsel regexnejoinsel regexnesel
+ regexp_matches regexp_replace regexp_split_to_array regexp_split_to_table regoperatorin regoperatorout regoperatorrecv
+ regoperatorsend regoperin regoperout regoperrecv regopersend regprocedurein regprocedureout
+ regprocedurerecv regproceduresend regprocin regprocout regprocrecv regprocsend regr_avgx
+ regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy
+ regr_syy regtypein regtypeout regtyperecv regtypesend reltime reltimeeq
+ reltimege reltimegt reltimein reltimele reltimelt reltimene reltimeout
+ reltimerecv reltimesend reverse round row_number row_to_json
+ scalargtjoinsel scalargtsel scalarltjoinsel scalarltsel
+ session_user set_config set_masklen setseed setval setweight shell_in
+ shell_out shift_jis_2004_to_euc_jis_2004 shift_jis_2004_to_utf8 shobj_description sign similar_escape sin
+ sjis_to_euc_jp sjis_to_mic sjis_to_utf8 slope smgreq smgrin smgrne
+ smgrout spg_kd_choose spg_kd_config spg_kd_inner_consistent spg_kd_picksplit spg_quad_choose spg_quad_config
+ spg_quad_inner_consistent spg_quad_leaf_consistent spg_quad_picksplit spg_text_choose spg_text_config spg_text_inner_consistent spg_text_leaf_consistent
+ spg_text_picksplit spgbeginscan spgbuild spgbuildempty spgbulkdelete spgcanreturn spgcostestimate
+ spgendscan spggetbitmap spggettuple spginsert spgmarkpos spgoptions spgrescan
+ spgrestrpos spgvacuumcleanup sqrt statement_timestamp stddev stddev_pop stddev_samp
+ string_agg string_agg_finalfn string_agg_transfn string_to_array strip sum
+ tan text text_ge text_gt text_larger
+ text_le text_lt text_pattern_ge text_pattern_gt text_pattern_le text_pattern_lt text_smaller
+ textanycat textcat texteq texticlike texticnlike texticregexeq texticregexne
+ textin textlen textlike textne textnlike textout textrecv
+ textregexeq textregexne textsend thesaurus_init thesaurus_lexize tideq tidge
+ tidgt tidin tidlarger tidle tidlt tidne tidout
+ tidrecv tidsend tidsmaller time time_cmp time_eq time_ge
+ time_gt time_hash time_in time_larger time_le time_lt time_mi_interval
+ time_mi_time time_ne time_out time_pl_interval time_recv time_send time_smaller
+ time_transform timedate_pl timemi timenow timepl timestamp timestamp_cmp
+ timestamp_cmp_date timestamp_cmp_timestamptz timestamp_eq timestamp_eq_date timestamp_eq_timestamptz timestamp_ge timestamp_ge_date
+ timestamp_ge_timestamptz timestamp_gt timestamp_gt_date timestamp_gt_timestamptz timestamp_hash timestamp_in timestamp_larger
+ timestamp_le timestamp_le_date timestamp_le_timestamptz timestamp_lt timestamp_lt_date timestamp_lt_timestamptz timestamp_mi
+ timestamp_mi_interval timestamp_ne timestamp_ne_date timestamp_ne_timestamptz timestamp_out timestamp_pl_interval timestamp_recv
+ timestamp_send timestamp_smaller timestamp_sortsupport timestamp_transform timestamptypmodin timestamptypmodout timestamptz
+ timestamptz_cmp timestamptz_cmp_date timestamptz_cmp_timestamp timestamptz_eq timestamptz_eq_date timestamptz_eq_timestamp timestamptz_ge
+ timestamptz_ge_date timestamptz_ge_timestamp timestamptz_gt timestamptz_gt_date timestamptz_gt_timestamp timestamptz_in timestamptz_larger
+ timestamptz_le timestamptz_le_date timestamptz_le_timestamp timestamptz_lt timestamptz_lt_date timestamptz_lt_timestamp timestamptz_mi
+ timestamptz_mi_interval timestamptz_ne timestamptz_ne_date timestamptz_ne_timestamp timestamptz_out timestamptz_pl_interval timestamptz_recv
+ timestamptz_send timestamptz_smaller timestamptztypmodin timestamptztypmodout timetypmodin timetypmodout timetz
+ timetz_cmp timetz_eq timetz_ge timetz_gt timetz_hash timetz_in timetz_larger
+ timetz_le timetz_lt timetz_mi_interval timetz_ne timetz_out timetz_pl_interval timetz_recv
+ timetz_send timetz_smaller timetzdate_pl timetztypmodin timetztypmodout timezone tinterval
+ tintervalct tintervalend tintervaleq tintervalge tintervalgt tintervalin tintervalle
+ tintervalleneq tintervallenge tintervallengt tintervallenle tintervallenlt tintervallenne tintervallt
+ tintervalne tintervalout tintervalov tintervalrecv tintervalrel tintervalsame tintervalsend
+ tintervalstart to_json to_tsquery to_tsvector transaction_timestamp trigger_out trunc ts_debug
+ ts_headline ts_lexize ts_match_qv ts_match_tq ts_match_tt ts_match_vq ts_parse
+ ts_rank ts_rank_cd ts_rewrite ts_stat ts_token_type ts_typanalyze tsmatchjoinsel
+ tsmatchsel tsq_mcontained tsq_mcontains tsquery_and tsquery_cmp tsquery_eq tsquery_ge
+ tsquery_gt tsquery_le tsquery_lt tsquery_ne tsquery_not tsquery_or tsqueryin
+ tsqueryout tsqueryrecv tsquerysend tsrange tsrange_subdiff tstzrange tstzrange_subdiff
+ tsvector_cmp tsvector_concat tsvector_eq tsvector_ge tsvector_gt tsvector_le tsvector_lt
+ tsvector_ne tsvectorin tsvectorout tsvectorrecv tsvectorsend txid_current txid_current_snapshot
+ txid_snapshot_in txid_snapshot_out txid_snapshot_recv txid_snapshot_send txid_snapshot_xip txid_snapshot_xmax txid_snapshot_xmin
+ txid_visible_in_snapshot uhc_to_utf8 unknownin unknownout unknownrecv unknownsend unnest
+ upper_inc upper_inf utf8_to_ascii utf8_to_big5 utf8_to_euc_cn utf8_to_euc_jis_2004 utf8_to_euc_jp
+ utf8_to_euc_kr utf8_to_euc_tw utf8_to_gb18030 utf8_to_gbk utf8_to_iso8859 utf8_to_iso8859_1 utf8_to_johab
+ utf8_to_koi8r utf8_to_koi8u utf8_to_shift_jis_2004 utf8_to_sjis utf8_to_uhc utf8_to_win uuid_cmp
+ uuid_eq uuid_ge uuid_gt uuid_hash uuid_in uuid_le uuid_lt
+ uuid_ne uuid_out uuid_recv uuid_send var_pop var_samp varbit
+ varbit_in varbit_out varbit_recv varbit_send varbit_transform varbitcmp varbiteq
+ varbitge varbitgt varbitle varbitlt varbitne varbittypmodin varbittypmodout
+ varchar varying varchar_transform varcharin varcharout varcharrecv varcharsend varchartypmodin
+ varchartypmodout variance version void_in void_out void_recv void_send
+ width width_bucket win1250_to_latin2 win1250_to_mic win1251_to_iso win1251_to_koi8r win1251_to_mic
+ win1251_to_win866 win866_to_iso win866_to_koi8r win866_to_mic win866_to_win1251 win_to_utf8 xideq
+ xideqint4 xidin xidout xidrecv xidsend xml xml_in xmlcomment xpath xpath_exists table_to_xmlschema
+ query_to_xmlschema cursor_to_xmlschema table_to_xml_and_xmlschema query_to_xml_and_xmlschema
+ schema_to_xml schema_to_xmlschema schema_to_xml_and_xmlschema database_to_xml database_to_xmlschema xmlroot
+ database_to_xml_and_xmlschema table_to_xml query_to_xmlcursor_to_xml xmlcomment xmlconcat xmlelement xmlforest
+ xml_is_well_formed_content xml_is_well_formed_document xml_is_well_formed xml_out xml_recv xml_send xmlagg
+ xmlpi query_to_xml cursor_to_xml xmlserialize
+ );
my @copy_keywords = ( 'STDIN', 'STDOUT' );
my %symbols = (
- '=' => '=', '<' => '<', '>' => '>', '|' => '|', ',' => ',', '.' => '.', '+' => '+', '-' => '-',
- '*' => '*', '/' => '/', '!=' => '!=', '%' => '%', '<=' => '<=', '>=' => '>=', '<>' => '<>'
+ '=' => '=', '<' => '<', '>' => '>', '|' => '|', ',' => ',', '.' => '.', '+' => '+', '-' => '-',
+ '*' => '*', '/' => '/', '!=' => '!=', '%' => '%', '<=' => '<=', '>=' => '>=', '<>' => '<>'
);
my @brackets = ( '(', ')' );
# All setting and modification of dicts is done, can set them now to $self->{'dict'}->{...}
$self->{ 'dict' }->{ 'pg_keywords' } = \@pg_keywords;
+ $self->{ 'dict' }->{ 'pg_types' } = \@pg_types;
$self->{ 'dict' }->{ 'sql_keywords' } = \@sql_keywords;
- $self->{ 'dict' }->{ 'pg_functions' } = \@pg_functions;
+ $self->{ 'dict' }->{ 'pg_functions' } = ();
+ map { $self->{ 'dict' }->{ 'pg_functions' }{$_} = ''; } @pg_functions;
$self->{ 'dict' }->{ 'copy_keywords' } = \@copy_keywords;
$self->{ 'dict' }->{ 'symbols' } = \%symbols;
$self->{ 'dict' }->{ 'brackets' } = \@brackets;
# Try to auto detect the string separator if none are provided.
# Note that default single quote separtor is natively supported.
if ($#dynsep == -1) {
- # if a dollar sign is found after EXECUTE then the following string
- # until an other dollar is found will be understand as a text delimiter
- @dynsep = $$str =~ /EXECUTE\s+(\$[^\$\s]*\$)/igs;
+ # if a dollar sign is found after EXECUTE then the following string
+ # until an other dollar is found will be understand as a text delimiter
+ @dynsep = $$str =~ /EXECUTE\s+(\$[^\$\s]*\$)/igs;
}
my $idx = 0;
foreach my $sep (@dynsep) {
- while ($$str =~ s/(\Q$sep\E.*?\Q$sep\E)/TEXTVALUE$idx/s) {
- $self->{dynamic_code}{$idx} = $1;
- $idx++;
- }
+ while ($$str =~ s/(\Q$sep\E.*?\Q$sep\E)/TEXTVALUE$idx/s) {
+ $self->{dynamic_code}{$idx} = $1;
+ $idx++;
+ }
}
- # Replace any COMMENT constant between single quote
- while ($$str =~ s/IS\s+('[^;]+);/IS TEXTVALUE$idx;/s) {
- $self->{dynamic_code}{$idx} = $1;
- $idx++;
+ # Replace any COMMENT constant between single quote
+ while ($$str =~ s/IS\s+('(?:.*?)')\s*;/IS TEXTVALUE$idx;/s) {
+ $self->{dynamic_code}{$idx} = $1;
+ $idx++;
}
}
sub _restore_dynamic_code
{
- my ($self, $str) = @_;
+ my ($self, $str) = @_;
+
+ $$str =~ s/TEXTVALUE(\d+)/$self->{dynamic_code}{$1}/gs;
+
+}
+
+=head2 _quote_operator
+
+Internal function used to quote operator with multiple character
+to be tokenized as a single word.
+The original values are restored with function _restore_operator().
+
+=cut
+
+sub _quote_operator
+{
+ my ($self, $str) = @_;
- $$str =~ s/TEXTVALUE(\d+)/$self->{dynamic_code}{$1}/gs;
+ while ($$str =~ s/((?:CREATE|DROP|ALTER)\s+OPERATOR\s+(?:IF\s+EXISTS)?)\s*((:?[a-z0-9]+\.)?[\+\-\*\/<>=\~\!\@\#\%\^\&\|\`\?]+)\s*/$1 "$2" /is) {
+ push(@{ $self->{operator} }, $2) if (!grep(/^\Q$2\E$/, @{ $self->{operator} }));
+ }
+ my $idx = 0;
+ while ($$str =~ s/(NEGATOR|COMMUTATOR)\s*=\s*([^,\)\s]+)/\U$1\E$idx/is) {
+ $self->{uc($1)}{$idx} = "$1 = $2";
+ $idx++;
+ }
}
-=head2 _remove_comments (OBSOLETE)
+=head2 _restore_operator
+
+Internal function used to restore operator that was removed
+by the _quote_operator() method.
+
+=cut
+
+sub _restore_operator
+{
+ my ($self, $str) = @_;
+
+ foreach my $op (@{ $self->{operator} })
+ {
+ $$str =~ s/"$op"/$op/gs;
+ }
+ if (exists $self->{COMMUTATOR}) {
+ $$str =~ s/COMMUTATOR(\d+)/$self->{COMMUTATOR}{$1}/igs;
+ }
+ if (exists $self->{NEGATOR}) {
+ $$str =~ s/NEGATOR(\d+)/$self->{NEGATOR}{$1}/igs;
+ }
+}
+
+=head2 _remove_comments
Internal function used to remove comments in SQL code
-to simplify the work of the parser. Comments are restored
-with the _restore_comments() method.
+to simplify the work of the wrap_lines. Comments must be
+restored with the _restore_comments() method.
=cut
sub _remove_comments
{
- my ($self, $content) = @_;
+ my $self = shift;
my $idx = 0;
- while ($$content =~ s/(\/\*(.*?)\*\/)/PGF_COMMENT${idx}A/s) {
- $self->{'comments'}{"PGF_COMMENT${idx}A"} = $1;
- $idx++;
+ while ($self->{ 'content' } =~ s/(\/\*(.*?)\*\/)/PGF_COMMENT${idx}A/s) {
+ $self->{'comments'}{"PGF_COMMENT${idx}A"} = $1;
+ $idx++;
}
- my @lines = split(/\n/, $$content);
+ my @lines = split(/\n/, $self->{ 'content' });
for (my $j = 0; $j <= $#lines; $j++) {
- $lines[$j] //= '';
- # Extract multiline comments as a single placeholder
- my $old_j = $j;
- my $cmt = '';
- while ($lines[$j] =~ /^(\s*\-\-.*)$/) {
- $cmt .= "$1\n";
- $j++;
- }
- if ( $j > $old_j ) {
- chomp($cmt);
- $lines[$old_j] =~ s/^(\s*\-\-.*)$/PGF_COMMENT${idx}A/;
- $self->{'comments'}{"PGF_COMMENT${idx}A"} = $cmt;
- $idx++;
- $j--;
- while ($j > $old_j) {
- delete $lines[$j];
- $j--;
- }
- }
- if ($lines[$j] =~ s/(\s*\-\-.*)$/PGF_COMMENT${idx}A/) {
- $self->{'comments'}{"PGF_COMMENT${idx}A"} = $1;
- chomp($self->{'comments'}{"PGF_COMMENT${idx}A"});
- $idx++;
- }
-
- # Mysql supports differents kinds of comment's starter
- if ( ($lines[$j] =~ s/(\s*COMMENT\s+'.*)$/PGF_COMMENT${idx}A/) ||
- ($lines[$j] =~ s/(\s*\# .*)$/PGF_COMMENT${idx}A/) ) {
- $self->{'comments'}{"PGF_COMMENT${idx}A"} = $1;
- chomp($self->{'comments'}{"PGF_COMMENT${idx}A"});
- # Normalize start of comment
- $self->{'comments'}{"PGF_COMMENT${idx}A"} =~ s/^(\s*)COMMENT/$1\-\- /;
- $self->{'comments'}{"PGF_COMMENT${idx}A"} =~ s/^(\s*)\#/$1\-\- /;
- $idx++;
- }
+ $lines[$j] //= '';
+ # Extract multiline comments as a single placeholder
+ my $old_j = $j;
+ my $cmt = '';
+ while ($j <= $#lines && $lines[$j] =~ /^(\s*\-\-.*)$/) {
+ $cmt .= "$1\n";
+ $j++;
+ }
+ if ( $j > $old_j ) {
+ chomp($cmt);
+ $lines[$old_j] =~ s/^(\s*\-\-.*)$/PGF_COMMENT${idx}A/;
+ $self->{'comments'}{"PGF_COMMENT${idx}A"} = $cmt;
+ $idx++;
+ $j--;
+ while ($j > $old_j) {
+ delete $lines[$j];
+ $j--;
+ }
+ }
+ if ($lines[$j] =~ s/(\s*\-\-.*)$/PGF_COMMENT${idx}A/) {
+ $self->{'comments'}{"PGF_COMMENT${idx}A"} = $1;
+ chomp($self->{'comments'}{"PGF_COMMENT${idx}A"});
+ $idx++;
+ }
+
+ # Mysql supports differents kinds of comment's starter
+ if ( ($lines[$j] =~ s/(\s*COMMENT\s+'.*)$/PGF_COMMENT${idx}A/) ||
+ ($lines[$j] =~ s/(\s*\# .*)$/PGF_COMMENT${idx}A/) ) {
+ $self->{'comments'}{"PGF_COMMENT${idx}A"} = $1;
+ chomp($self->{'comments'}{"PGF_COMMENT${idx}A"});
+ # Normalize start of comment
+ $self->{'comments'}{"PGF_COMMENT${idx}A"} =~ s/^(\s*)COMMENT/$1\-\- /;
+ $self->{'comments'}{"PGF_COMMENT${idx}A"} =~ s/^(\s*)\#/$1\-\- /;
+ $idx++;
+ }
}
- $$content = join("\n", @lines);
+ $self->{ 'content' } = join("\n", @lines);
# Replace subsequent comment by a single one
- while ($$content =~ s/(PGF_COMMENT\d+A\s*PGF_COMMENT\d+A)/PGF_COMMENT${idx}A/s) {
- $self->{'comments'}{"PGF_COMMENT${idx}A"} = $1;
- $idx++;
+ while ($self->{ 'content' } =~ s/(PGF_COMMENT\d+A\s*PGF_COMMENT\d+A)/PGF_COMMENT${idx}A/s) {
+ $self->{'comments'}{"PGF_COMMENT${idx}A"} = $1;
+ $idx++;
}
}
sub _restore_comments
{
- my ($self, $content) = @_;
+ my $self = shift;
- while ($$content =~ s/(PGF_COMMENT\d+A)[\n]*/$self->{'comments'}{$1}\n/s) { delete $self->{'comments'}{$1}; };
+ while ($self->{ 'content' } =~ s/(PGF_COMMENT\d+A)[\n]*/$self->{'comments'}{$1}\n/s) { delete $self->{'comments'}{$1}; };
}
+=head2 wrap_lines
+
+Internal function used to wrap line at a certain length.
+
+=cut
+
+sub wrap_lines
+{
+ my $self = shift;
+
+ return if (!$self->{'wrap_limit'} || !$self->{ 'content' });
+
+ $self->_remove_comments();
+
+ my @lines = split(/\n/, $self->{ 'content' });
+ $self->{ 'content' } = '';
+
+ foreach my $l (@lines)
+ {
+ # Remove and store the indentation of the line
+ my $indent = '';
+ if ($l =~ s/^(\s+)//) {
+ $indent = $1;
+ }
+ if (length($l) > $self->{'wrap_limit'} + ($self->{'wrap_limit'}*10/100))
+ {
+ $Text::Wrap::columns = $self->{'wrap_limit'};
+ my $t = wrap($indent, " "x$self->{ 'spaces' } . $indent, $l);
+ $self->{ 'content' } .= "$t\n";
+ } else {
+ $self->{ 'content' } .= $indent . "$l\n";
+ }
+ }
+
+ $self->_restore_comments() if ($self->{ 'content' });
+
+ return;
+}
=head1 AUTHOR