{
type => 'Identifier',
- element1 => Scalar,
- element2 => Scalar,
- element3 => Scalar,
+ elements => [ Scalar ],
}
-If element3 exists, then element2 must exist. element1 must always exist. If a
-given element exists, then it must be defined and of non-zero length.
+All values in elements must be defined.
Visitors are expected to, by default, quote all identifiers according to the SQL
dialect's quoting scheme.
=head3 Value
-A Value is a Perl scalar. Depending on the type, a Visitor may be able to make
-certain decisions.
+A Value is a Perl scalar. Depending on the subtype, a Visitor may be able to
+make certain decisions. The following are the minimally-valid subtypes:
=over 4
{
type => 'Operator',
op => String,
- args => ExpressionList,
+ args => [
+ Expression,
+ ],
}
Operators have a cardinality, or expected number of arguments. Some operators,
Subqueries, when expressed in SQL, must be bounded by parentheses.
+=head3 Alias
+
+An Alias is any place where the construct "X as Y" appears. While the "as Y" is
+often optional, the AST will make it required.
+
+The hash will be structured as follows:
+
+ {
+ type => 'Alias',
+ value => Expression,
+ as => Identifier,
+ }
+
=head3 Expression
An Expression can be any one of the following:
=item * Subquery
+=item * Alias
+
=back
An Expression is a meta-syntactic unit. An "Expression" unit will never appear
within the AST. It acts as a junction.
-=head3 ExpressionList
-
-An ExpressionList is a list of Expressions, generally separated by commas
-(though other separators may be appropriate at times or for different SQL
-dialects). An null separator may also be used.
-
-The hash for an ExpressionList is as follows:
-
- {
- type => 'ExpressionList',
- separator => ',',
- elements => Array of Expressions,
- }
-
-An ExpressionList is always rendered in SQL with parentheses around it.
-
=head3 Nesting
There is no specific operator or nodetype for nesting. Instead, nesting is
optional in another. Detecting and enforcing those engine-specific restrictions
is the responsibility of the Visitor object.
-The clauses are defined with a yacc-like syntax. The various parts are:
+The following clauses are expected to be handled by Visitors for each statement:
=over 4
-=item * :=
+=item * select
+
+=over 4
+
+=item * select
+
+=item * tables
-This means "defined" and is used to create a new term to be used below.
+=item * where
-=item * []
+=item * orderby
-This means optional and indicates that the items within it are optional.
+=item * groupby
-=item * []*
+=back
+
+=item * insert
+
+=over 4
+
+=item * tables
-This means optional and repeating as many times as desired.
+=item * set
+
+=back
+
+There are RDBMS-specific variations of the INSERT statement, such the one in
+MySQL's
+
+=item * update
-=item * |
+=over 4
-This means alternation. It is a binary operator and indicates that either the
-left or right hand sides may be used, but not both.
+=item * tables
-=item * C<< <> >>
+=item * set
-This is a grouping construct. It means that all elements within this construct
-are treated together for the purposes of optional, repeating, alternation, etc.
+=item * where
=back
-The expected clauses are (name and structure):
+=item * delete
-=head3 select
+=over 4
-This corresponds to the SELECT clause of a SELECT statement.
+=item * tables
-A select clause unit is an array of one or more SelectComponent units.
+=item * where
-The hash for a SelectComponent unit is composed as follows:
+=back
- {
- type => 'SelectComponent',
- value => Expression,
- as => String,
- }
+=back
-The 'as' component is optional. Visitors may choose to make it required in
-certain situations.
+The expected clauses are (name and structure):
+
+=head3 select
+
+This corresponds to the SELECT clause of a SELECT statement.
+
+A select clause unit is an array of one or more Expressions.
=head3 tables
all of them and it is up to the Visitor object constructing the actual SQL to
validate and/or use what is provided as appropriate.
-A TableJoin is a junction of the following elements:
-
-=over 4
-
-=item * TableIdentifier
-
-=item * Operator
-
-=back
-
-The hash for a TableIdentifier will be composed as follows:
-
- # TableIdentifier
- {
- type => 'TableIdentifier',
- value => Expression,
- as => String,
- }
-
-The value should be either an Identifier or a SubQuery.
+A tables clause is an Expression.
The hash for an Operator within a tables clause will be composed as follows:
type => 'Operator',
op => '< LEFT|RIGHT|FULL [ OUTER ] > | INNER | CROSS',
on => Expression,
+ args => [ Expression ],
}
A USING clause is syntactic sugar for an ON clause and, as such, is not provided
This corresponds to the SET clause in an INSERT or UPDATE statement.
-A set clause is composed as follows:
-
- SetComponent := Identifier = Expression
-
- SetComponent [ , SetComponent ]*
-
-=head3 columns
+The hash for an set clause will be composed as follows:
-This corresponds to the optional list of columns in an INSERT statement.
-
-A columns clause is an IdentifierList and the unit is composed as follows:
-
- columns => [
- Identifier,
- [ Identifier, ]*
- ],
-
-=head3 values
-
-This corresponds to the VALUES clause in an INSERT statement.
-
-A values clause is an ExpressionList and the unit is composed as follows:
-
- values => [
- Expression,
- [ Expression, ]*
- ],
+ {
+ type => 'Set',
+ args => [
+ [ Identifier ],
+ [ Expresion ],
+ ],
+ }
-If there is a columns clause, the number of entries in the values clause must be
-equal to the number of entries in the columns clause.
+The args is an array that is organized as follows: The first element is an array of
+Identifiers for the columns being set. The following arrays are Expressions describing
+the values. The various arrays should be the same length. The array of Identifiers can
+be omitted.
=head3 orderby
{
type => 'OrderbyComponent',
- value => < Identifier | Number >
+ value => Expression,
dir => '< ASC | DESC >',
}
-The dir element, if omitted, will be defaulted to ASC by the AST. The number
-corresponds to a column in the select clause.
+The value should either be an Identifier or a Number. The dir element, if
+omitted, will be defaulted to ASC by the AST. The number corresponds to a column
+in the select clause.
=head3 groupby
{
type => 'GroupbyComponent',
- value => < Identifier | Number >
+ value => Expression,
}
-The number corresponds to a column in the select clause.
+The value should either be an Identifier or a Number. The number corresponds to
+a column in the select clause.
+
+=head2 Possible RDBMS-specific clauses
+
+The following clauses are provided as examples for RDBMS-specific elements. They
+are B<not> expected to be supported by all Visitors. Visitors may choose whether
+or not to throw on an unexpected clause, though it is strongly recommended.
=head3 rows
This corresponds to the clause that is used in some RDBMS engines to limit the
-number of rows returned by a query. In MySQL, this would be the LIMIT clause.
+number of rows returned by a SELECT statement. In MySQL, this would be the LIMIT
+clause.
The hash for a rows clause is composed as follows:
{
- type => 'Rows',
start => Number,
count => Number,
}
This corresponds to the clause that is used in some RDBMS engines to provide for
an adjacency-list query.
-A connectby clause is composed as follows:
+The hash for a for clause is composed as follows:
+
+ {
+ start_with => [
+ Expression,
+ ],
+ connect_by => {
+ option => '< PRIOR | NOCYCLE >'
+ cond => [
+ Expression,
+ ],
+ },
+ order_siblings => orderby-clause,
+ }
- Identifier, WhereExpression
+Both the start_with and order_siblings clauses are optional.
=head1 TODO
=item * sproc unit
+=item * UNION, UNION ALL, and MINUS
+
+=item * INSERT INTO <table> SELECT ...
+
+=item * INSERT INTO <table> SET ...
+
+=item * UPDATE foo me SET bar = 1 FROM fnord f WHERE me.col1 = f.frobinator
+
+=item * INSERT moves to using the SET terminology with Visitor dwimming
+
=back
+Convert INSERT and UPDATE into ->populate form.
+
=head1 AUTHORS
robkinyon: Rob Kinyon C<< <rkinyon@cpan.org> >>