%{super()},
in => $self->can('_in'),
not_in => $self->can('_in'),
+ between => $self->can('_between'),
+ not_between => $self->can('_between'),
and => $self->can('_recurse_where'),
or => $self->can('_recurse_where'),
map { +"$_" => $self->can("_$_") } qw/
value
- name
+ identifier
true
false
expr
return join(' ', @output);
}
+ method _update(AST $ast) {
+
+ for (qw/columns values tablespec/) {
+ confess "'$_' is required in update AST with " . dump ($ast)
+ unless exists $ast->{$_};
+ }
+
+ }
+
method _join(HashRef $ast) {
# TODO: Validate join type
return $output;
}
- method _name(AST $ast) {
- my @names = @{$ast->{args}};
+ method _identifier(AST $ast) {
+ my @names = @{$ast->{elements}};
- my $sep = $self->name_separator;
+ my $sep = $self->ident_separator;
my $quote = $self->is_quoting
? $self->quote_chars
: [ '' ];
my $post;
$post = pop @names if $names[-1] eq '*';
- my $ret =
- $quote->[0] .
- join( $join, @names ) .
- $quote->[-1];
+ my $ret;
+ $ret = $quote->[0] .
+ join( $join, @names ) .
+ $quote->[-1]
+ if @names;
+
+ $ret = $ret
+ ? $ret . $sep . $post
+ : $post
+ if defined $post;
+
- $ret .= $sep . $post if defined $post;
return $ret;
}
method _list(AST $ast) {
+ return "" unless $ast->{args};
+
my @items = is_ArrayRef($ast->{args})
? @{$ast->{args}}
: $ast->{args};
if ($_->{-type} eq 'expr' && $_->{op} =~ /^(and|or)$/) {
my $sub_prio = $SQL::Abstract::PRIO{$1};
- if ($sub_prio <= $prio) {
+ if ($sub_prio == $prio) {
+ # When the element below has same priority, i.e. 'or' as a child of
+ # 'or', dont produce extra brackets
push @output, $self->_recurse_where($_);
} else {
push @output, '(' . $self->_recurse_where($_) . ')';
croak "'$op' is not a valid AST type in an expression with " . dump($ast)
if $ast->{-type} ne 'expr';
- croak "'$op' is not a valid operator in an expression with " . dump($ast);
+ # This is an attempt to do some form of validation on function names. This
+ # might end up being a bad thing.
+ croak "'$op' is not a valid operator in an expression with " . dump($ast)
+ if $op =~ /\W/;
+
+ return $self->_generic_function_op($ast);
}
my ($lhs, $rhs) = @{$ast->{args}};
my $op = $ast->{op};
+ # IS NOT? NULL
+ if ($rhs->{-type} eq 'value' && !defined $rhs->{value} &&
+ ($op eq '==' || $op eq '!='))
+ {
+ return $self->_expr($lhs) .
+ ($op eq '==' ? " IS " : " IS NOT ") .
+ "NULL";
+ }
+
join (' ', $self->_expr($lhs),
$self->binop_mapping($op) || croak("Unknown binary operator $op"),
$self->_expr($rhs)
);
}
+ method _generic_function_op(AST $ast) {
+ my $op = $ast->{op};
+
+ return "$op(" . $self->_list($ast) . ")";
+ }
+
method _in(AST $ast) {
my ($field,@values) = @{$ast->{args}};
")";
}
- method _generic_func(ArrayRef $ast) {
+ method _between(AST $ast) {
+
+ my ($field,@values) = @{$ast->{args}};
+
+ my $not = ($ast->{op} =~ /^not_/) ? " NOT" : "";
+ croak "between requires 3 arguments: " . dump($ast)
+ unless @values == 2;
+
+ # The brackets are to work round an issue with SQL::A::Test
+ return "(" .
+ $self->_expr($field) .
+ $not .
+ " BETWEEN " .
+ join(" AND ", map { $self->dispatch($_) } @values ) .
+ ")";
}
# 'constants' that are portable across DBs