3742 lines
110 KiB
Perl
3742 lines
110 KiB
Perl
|
|
/*
|
||
|
|
|
||
|
|
----
|
||
|
|
This file is part of SECONDO.
|
||
|
|
|
||
|
|
Copyright (C) 2004, University in Hagen, Department of Computer Science,
|
||
|
|
Database Systems for New Applications.
|
||
|
|
|
||
|
|
SECONDO is free software; you can redistribute it and/or modify
|
||
|
|
it under the terms of the GNU General Public License as published by
|
||
|
|
the Free Software Foundation; either version 2 of the License, or
|
||
|
|
(at your option) any later version.
|
||
|
|
|
||
|
|
SECONDO is distributed in the hope that it will be useful,
|
||
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
|
GNU General Public License for more details.
|
||
|
|
|
||
|
|
You should have received a copy of the GNU General Public License
|
||
|
|
along with SECONDO; if not, write to the Free Software
|
||
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
|
----
|
||
|
|
|
||
|
|
//paragraph [10] title: [{\Large \bf ] [}]
|
||
|
|
//characters [1] formula: [$] [$]
|
||
|
|
//[ae] [\"{a}]
|
||
|
|
//[oe] [\"{o}]
|
||
|
|
//[ue] [\"{u}]
|
||
|
|
//[ss] [{\ss}]
|
||
|
|
//[Ae] [\"{A}]
|
||
|
|
//[Oe] [\"{O}]
|
||
|
|
//[Ue] [\"{U}]
|
||
|
|
//[**] [$**$]
|
||
|
|
//[star] [$*$]
|
||
|
|
//[->] [$\rightarrow$]
|
||
|
|
//[toc] [\tableofcontents]
|
||
|
|
//[=>] [\verb+=>+]
|
||
|
|
//[:Section Translation] [\label{sec:translation}]
|
||
|
|
//[Section Translation] [Section~\ref{sec:translation}]
|
||
|
|
//[:Section 4.1.1] [\label{sec:4.1.1}]
|
||
|
|
//[Section 4.1.1] [Section~\ref{sec:4.1.1}]
|
||
|
|
//[Figure pog1] [Figure~\ref{fig:pog1.eps}]
|
||
|
|
//[Figure pog2] [Figure~\ref{fig:pog2.eps}]
|
||
|
|
//[newpage] [\newpage]
|
||
|
|
|
||
|
|
August 2008, Burkart Poneleit. Initial Version
|
||
|
|
|
||
|
|
[toc]
|
||
|
|
|
||
|
|
18.1 Transforming nested queries to their canonical form
|
||
|
|
|
||
|
|
This file enables the SECONDO optimizer to process subqueries or nested queries formulated in SQL syntax.
|
||
|
|
A subquery or nested query is a fully-fledged query contained in another query.
|
||
|
|
For example
|
||
|
|
|
||
|
|
---- select *
|
||
|
|
from staedte
|
||
|
|
where plz in (select p:plz from plz as p)
|
||
|
|
----
|
||
|
|
|
||
|
|
will yield all entries of relation staedte where plz contains an entry with matching plz.
|
||
|
|
Depending on its form, subqueries can yield scalar results, single tuple results or table results.
|
||
|
|
Subqueries whith a scalar result can be used in the attribute list, the from-clause and the where-clause.
|
||
|
|
If the subquery is not correlated with the outer query, i.e. does not reference any attribute of the outer relation
|
||
|
|
in its predicates, it can be evaluated independently of the outer query. Subqueries in predicates can always be evaluated
|
||
|
|
by the so called nested-iteration method. The subuqery will be evaluated for every result tuple of the outer query. As
|
||
|
|
there are always canonical forms of the queries which do not use nesting and yield the same result,
|
||
|
|
|
||
|
|
|
||
|
|
Queries containing subqueries will be rewritten by this module to an equivalent canonical form.
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
Facts about comparison operators
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
%isComparisonOp(=).
|
||
|
|
%isComparisonOp(<=).
|
||
|
|
%isComparisonOp(>=).
|
||
|
|
%isComparisonOp(<).
|
||
|
|
%isComparisonOp(>).
|
||
|
|
%isComparisonOp(<>).
|
||
|
|
|
||
|
|
% use operator properties based rules from ~operators.pl~
|
||
|
|
isComparisonOp(<>) :- isComparatorOp(#), !. % match prolog op to secondo op name
|
||
|
|
isComparisonOp(T) :- isComparatorOp(T), !.
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Some operator definitions
|
||
|
|
|
||
|
|
*/
|
||
|
|
:- op(700, xfx, <>).
|
||
|
|
%:- op(700, xfx, =+). % outer join operator
|
||
|
|
:- op(940, xfx, in).
|
||
|
|
:- op(941, xfx, not).
|
||
|
|
:- op(799, fy, left).
|
||
|
|
:- op(799, fy, outerjoin).
|
||
|
|
:- op(799, fy, right).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
---- isQuery(+Term)
|
||
|
|
----
|
||
|
|
|
||
|
|
This predicate is true, if the term is structurally a query formulated
|
||
|
|
in the sql syntax defined for secondo. Exceptions are ignored, if they
|
||
|
|
are caused by attribute references to attributes of relations not included
|
||
|
|
in the FROM-clause. This is needed to correctly handle subqueries with
|
||
|
|
correlated predicates.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
/*
|
||
|
|
NVK ADDED NR
|
||
|
|
Not anymore intended for top-level query lookup. See optimizer.pl\#callLookup for further information. This exception thing is really annoying during debugging, the exceptions are raised during the query rewriting phase, because this happens before the lookup phase, so there are no outer variables etc. known. To fix this, i added some more predicates to identify subqueries directly without to call the lookup, but it is still a workaround. This is based on the lookup(Query, \_) predicates within the optimizer.pl.
|
||
|
|
|
||
|
|
*/
|
||
|
|
isQuery(Query) :-
|
||
|
|
optimizerOption(nestedRelations),
|
||
|
|
!,
|
||
|
|
simplifiedIsQuery(Query).
|
||
|
|
% NVK ADDED NR END
|
||
|
|
|
||
|
|
isQuery(Query) :-
|
||
|
|
\+ optimizerOption(nestedRelations),
|
||
|
|
catch(callLookup(Query, _),
|
||
|
|
error_SQL(optimizer_lookupPred1(T, T)::unknownIdentifier::_),
|
||
|
|
true).
|
||
|
|
|
||
|
|
isQuery(Query) :-
|
||
|
|
\+ optimizerOption(nestedRelations),
|
||
|
|
catch(callLookup(Query, _),
|
||
|
|
error_SQL(optimizer_lookupPred(T, T)::malformedExpression::_),
|
||
|
|
true).
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Predicates to recognize nested queries. It looks for a nested query in
|
||
|
|
the select-, from- and where clause.
|
||
|
|
|
||
|
|
NVK NOTE: This is used nowhere.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
isNestedQuery(Query orderby _) :- isNestedQuery(Query).
|
||
|
|
isNestedQuery(Query groupby _) :- isNestedQuery(Query).
|
||
|
|
isNestedQuery(Query first _) :- isNestedQuery(Query).
|
||
|
|
isNestedQuery(Query last _) :- isNestedQuery(Query).
|
||
|
|
|
||
|
|
isNestedQuery(select _ from _ where PredList) :-
|
||
|
|
makeList(PredList, PredList2),
|
||
|
|
not(sublist(isSubqueryPred, PredList2, [])).
|
||
|
|
|
||
|
|
isNestedQuery(select AttrList from RelList where _) :-
|
||
|
|
isNestedQuery(select AttrList from RelList).
|
||
|
|
|
||
|
|
isNestedQuery(select AttrList from _) :-
|
||
|
|
makeList(AttrList, AttrList2),
|
||
|
|
not(sublist(isSubqueryAttr, AttrList2, [])).
|
||
|
|
|
||
|
|
isNestedQuery(select _ from RelList) :-
|
||
|
|
makeList(RelList, RelList2),
|
||
|
|
not(sublist(isQuery, RelList2, [])).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Predicates to recognize subqueries in attribute lists and attributes.
|
||
|
|
|
||
|
|
NVK NOTE: This is used nowhere.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
isSubqueryAttr(Attr as _) :-
|
||
|
|
isQuery(Attr).
|
||
|
|
|
||
|
|
isSubqueryAttr(Attr) :-
|
||
|
|
isQuery(Attr).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Predicates to recognize subqueries in predicate lists and predicates.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
% case negated predicates
|
||
|
|
isSubqueryPred(not(Pred)) :-
|
||
|
|
isSubqueryPred(Pred).
|
||
|
|
|
||
|
|
% case ~not in~
|
||
|
|
isSubqueryPred(Pred) :-
|
||
|
|
Pred =.. [not, Attr, in(Query)],
|
||
|
|
isSubqueryPred(Attr in(Query)).
|
||
|
|
|
||
|
|
% case simple nested predicate, binary operator
|
||
|
|
isSubqueryPred(Pred) :-
|
||
|
|
compound(Pred),
|
||
|
|
Pred =.. [Op, _, Subquery],
|
||
|
|
isSubqueryOp(Op),
|
||
|
|
isQuery(Subquery).
|
||
|
|
|
||
|
|
% case simple nested predicate, unary operator
|
||
|
|
isSubqueryPred(Pred) :-
|
||
|
|
compound(Pred),
|
||
|
|
Pred =.. [Op, Subquery],
|
||
|
|
isSubqueryOp(Op),
|
||
|
|
isQuery(Subquery).
|
||
|
|
|
||
|
|
% case quantified subquery
|
||
|
|
isSubqueryPred(Pred) :-
|
||
|
|
compound(Pred),
|
||
|
|
Pred =.. [Op, _, QuantifiedPred],
|
||
|
|
QuantifiedPred =.. [Quantifier, Subquery],
|
||
|
|
isComparisonOp(Op),
|
||
|
|
isQuantifier(Quantifier),
|
||
|
|
isQuery(Subquery).
|
||
|
|
|
||
|
|
% definition of subquery operators
|
||
|
|
isSubqueryOp(in).
|
||
|
|
isSubqueryOp(exists).
|
||
|
|
isSubqueryOp(Op) :-
|
||
|
|
isComparisonOp(Op).
|
||
|
|
|
||
|
|
% definition of quantifiers
|
||
|
|
isQuantifier(all).
|
||
|
|
isQuantifier(any).
|
||
|
|
/*
|
||
|
|
NVK NOTE: no preTransformNestedPredicate predicates are defined for this, so far as i can see, this ~some~ quantifier isn't working at all.
|
||
|
|
|
||
|
|
*/
|
||
|
|
%isQuantifier(some).
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Special handling for operator ~in~ which can be replaced by ~=~ as join operator,
|
||
|
|
when a subquery is transformed to its canonical form.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
subqueryToJoinOp(in, =).
|
||
|
|
subqueryToJoinOp(Op, Op).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Quantified predicates are transformed into an equivalent form based on aggregated queries.
|
||
|
|
The following predicates map the comparison operator to the specific aggregation operator
|
||
|
|
needed in the transformed query.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
anyToAggr(<, max).
|
||
|
|
anyToAggr(<=, max).
|
||
|
|
anyToAggr(>, min).
|
||
|
|
anyToAggr(>=, min).
|
||
|
|
|
||
|
|
allToAggr(<, min).
|
||
|
|
allToAggr(<=, min).
|
||
|
|
allToAggr(>, max).
|
||
|
|
allToAggr(>=, max).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Set containment operator ~in~ is translated with a ~set~ and
|
||
|
|
corresponding ~in~ operator of the collection algebra.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
constantType(attr(Var:Attr, _, _), Type) :-
|
||
|
|
isAttributeOf(Var:Attr, Rel as Var),
|
||
|
|
dcName2internalName(AttrName, Attr),
|
||
|
|
attrType(Rel:AttrName, Type).
|
||
|
|
|
||
|
|
constantType(attr(Attr,_ , _), Type) :-
|
||
|
|
isAttributeOf(Attr, Rel),
|
||
|
|
dcName2internalName(AttrName, Attr),
|
||
|
|
attrType(Rel:AttrName, Type).
|
||
|
|
|
||
|
|
constantType(attr2(Var:Attr, _, _), Type) :-
|
||
|
|
isAttributeOf(Var:Attr, Rel as Var),
|
||
|
|
dcName2internalName(AttrName, Attr),
|
||
|
|
attrType(Rel:AttrName, Type).
|
||
|
|
|
||
|
|
constantType(attr2(Attr,_ , _), Type) :-
|
||
|
|
isAttributeOf(Attr, Rel),
|
||
|
|
dcName2internalName(AttrName, Attr),
|
||
|
|
attrType(Rel:AttrName, Type).
|
||
|
|
|
||
|
|
constantType([Arg | Rest], Type) :-
|
||
|
|
not(Rest = []),
|
||
|
|
(constantType(Arg, Type) ; constantType(Rest, Type)).
|
||
|
|
|
||
|
|
constantType([Arg], Type) :-
|
||
|
|
not(is_list(Arg)),
|
||
|
|
constantType(Arg, Type).
|
||
|
|
|
||
|
|
constantType(AttrExpr, Type) :-
|
||
|
|
not(is_list(AttrExpr)),
|
||
|
|
AttrExpr =.. [_ | Args],
|
||
|
|
constantType(Args, Type).
|
||
|
|
|
||
|
|
clearSubqueryHandling :-
|
||
|
|
clear(streamRel), clear(streamName),
|
||
|
|
retractall(currentRels(_)),
|
||
|
|
retractall(sampleSize(_)), retractall(isJoinPred(_)).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Predicates for Type-A Queries. Evaluate the subquery and return the result.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
evaluateSubquery(CanonicalSubquery, Result) :-
|
||
|
|
nestingType(CanonicalSubquery, a),
|
||
|
|
optimize(CanonicalSubquery, SecondoQuery, _),
|
||
|
|
atom(SecondoQuery),
|
||
|
|
atom_concat('query ', SecondoQuery, QueryText),
|
||
|
|
secondo(QueryText, [_, Res]),
|
||
|
|
not(is_list(Res)),
|
||
|
|
typeConversion(Res, Result).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Convert the result to a datatype which can be used as a constant in the resulting plan.
|
||
|
|
Currently only conversion string constants into a list of characters is needed.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
typeConversion(Data, Result) :-
|
||
|
|
string_concat('"', Temp, Data),
|
||
|
|
string_concat(TempRes, '"', Temp),
|
||
|
|
my_string_to_list(TempRes, Result).
|
||
|
|
|
||
|
|
typeConversion(Result, Result).
|
||
|
|
|
||
|
|
/*
|
||
|
|
The following syntax for subqueries will recognized by SECONDO:
|
||
|
|
|
||
|
|
~in~
|
||
|
|
|
||
|
|
---- select <attr-list>
|
||
|
|
from <rel-list>
|
||
|
|
where attr in (<Subquery>)
|
||
|
|
----
|
||
|
|
|
||
|
|
~not in~
|
||
|
|
|
||
|
|
---- select <attr-list>
|
||
|
|
from <rel-list>
|
||
|
|
where attr not in(<Subquery>)
|
||
|
|
----
|
||
|
|
|
||
|
|
~exists~
|
||
|
|
|
||
|
|
---- select <attr-list>
|
||
|
|
from <rel-list>
|
||
|
|
where exists(<Subquery>)
|
||
|
|
----
|
||
|
|
|
||
|
|
~not exists~
|
||
|
|
|
||
|
|
---- select <attr-list>
|
||
|
|
from <rel-list>
|
||
|
|
where not exists(<Subquery>)
|
||
|
|
----
|
||
|
|
|
||
|
|
~$<$compop$>$ any~
|
||
|
|
|
||
|
|
---- select <attr-list>
|
||
|
|
from <rel-list>
|
||
|
|
where <compop> any(<Subquery>)
|
||
|
|
----
|
||
|
|
|
||
|
|
~$<$compop$>$ all~
|
||
|
|
|
||
|
|
---- select <attr-list>
|
||
|
|
from <rel-list>
|
||
|
|
where <compop> all(<Subquery>)
|
||
|
|
----
|
||
|
|
|
||
|
|
~in~ is equivalent to ~$=$ any~
|
||
|
|
|
||
|
|
~not in~ is equivalent to ~$<$$>$~ all
|
||
|
|
|
||
|
|
18.1.1 Rewriting of Subqueries
|
||
|
|
|
||
|
|
---- rewriteQueryForSubqueryProcessing(+QueryIn,-QueryOut)
|
||
|
|
|
||
|
|
----
|
||
|
|
|
||
|
|
Rewrites a query by transforming subqueries within ~QueryIn~ to their canonical form and unifies rewritten query with ~QueryOut~.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
:- dynamic(rewriteCache/2).
|
||
|
|
|
||
|
|
% all options deactivated, no subquery handling!
|
||
|
|
rewriteQueryForSubqueryProcessing(QueryIn, QueryIn) :-
|
||
|
|
not(optimizerOption(subqueries)), !.
|
||
|
|
|
||
|
|
% only translate subqueries, no unnesting
|
||
|
|
rewriteQueryForSubqueryProcessing(QueryIn, QueryOut) :-
|
||
|
|
not(optimizerOption(subqueryUnnesting)),
|
||
|
|
preTransform(QueryIn, QueryOut),
|
||
|
|
dm(subqueryUnnesting,['\nREWRITING: Subqueries\n\tIn: ',
|
||
|
|
QueryIn,'\n\tOut: ',
|
||
|
|
QueryOut,'\n\n']),
|
||
|
|
clearSubqueryHandling,
|
||
|
|
!.
|
||
|
|
|
||
|
|
% use query cache to find rewritten query
|
||
|
|
rewriteQueryForSubqueryProcessing(NestedQuery, CanonicalQuery) :-
|
||
|
|
rewriteCache(NestedQuery, CanonicalQuery),
|
||
|
|
!,
|
||
|
|
dm(subqueryUnnesting,['\nREWRITING: Subqueries\n\tIn: ',
|
||
|
|
NestedQuery,'\n\tOut: ',
|
||
|
|
CanonicalQuery,'\n\n']).
|
||
|
|
|
||
|
|
% nothing found in query cache, apply transformations
|
||
|
|
rewriteQueryForSubqueryProcessing(NestedQuery, CanonicalQuery) :-
|
||
|
|
transform(NestedQuery, CanonicalQuery),
|
||
|
|
retractall(rewriteCache(NestedQuery, _)),
|
||
|
|
assert(rewriteCache(NestedQuery, CanonicalQuery)),
|
||
|
|
dm(subqueryUnnesting,['\nREWRITING: Subqueries\n\tIn: ',
|
||
|
|
NestedQuery,'\n\tOut: ',
|
||
|
|
CanonicalQuery,'\n\n']).
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Apply Pre-Transformations, like replacing operators ~any~, ~all~ and ~exists~ with their generic transformation
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
|
||
|
|
preTransform(Query orderby Order, Query2 orderby Order) :-
|
||
|
|
preTransform(Query, Query2).
|
||
|
|
|
||
|
|
preTransform(Query groupby Group, Query2 groupby Group) :-
|
||
|
|
preTransform(Query, Query2).
|
||
|
|
|
||
|
|
preTransform(Query first N, Query2 first N) :-
|
||
|
|
preTransform(Query, Query2).
|
||
|
|
|
||
|
|
preTransform(Query last N, Query2 last N) :-
|
||
|
|
preTransform(Query, Query2).
|
||
|
|
|
||
|
|
preTransform(select Attrs from Rels where Preds,
|
||
|
|
select CanonicalAttrs
|
||
|
|
from CanonicalRels
|
||
|
|
where CanonicalPreds) :-
|
||
|
|
preTransformNestedPredicates(Attrs, CanonicalAttrs, Rels,
|
||
|
|
CanonicalRels, Preds, CanonicalPredList),
|
||
|
|
flatten(CanonicalPredList, CanonicalPreds).
|
||
|
|
|
||
|
|
preTransform(Query, Query).
|
||
|
|
|
||
|
|
preTransformNestedPredicates(Attrs, Attrs, Rels, Rels, [], []).
|
||
|
|
|
||
|
|
preTransformNestedPredicates(Attrs, Attrs2,
|
||
|
|
Rels, Rels2,
|
||
|
|
Pred, Pred2) :-
|
||
|
|
not(is_list(Pred)),
|
||
|
|
preTransformNestedPredicate(Attrs, Attrs2,
|
||
|
|
Rels, Rels2,
|
||
|
|
Pred, Pred2).
|
||
|
|
|
||
|
|
preTransformNestedPredicates(Attrs, Attrs2, Rels, Rels3,
|
||
|
|
[ Pred | Rest ],
|
||
|
|
[ Pred2 | Rest2 ]) :-
|
||
|
|
preTransformNestedPredicate(Attrs, Attrs2,
|
||
|
|
Rels, Rels2,
|
||
|
|
Pred, Pred2),
|
||
|
|
dc(subqueryUnnesting,
|
||
|
|
( not(Pred = Pred2)
|
||
|
|
-> dm(subqueryUnnesting, ['\nPredicate: ',
|
||
|
|
Pred,
|
||
|
|
'\nTransformedPredicate: ',
|
||
|
|
Pred2])
|
||
|
|
; true
|
||
|
|
)),
|
||
|
|
preTransformNestedPredicates(Attrs, Attrs2,
|
||
|
|
Rels2, Rels3,
|
||
|
|
Rest, Rest2).
|
||
|
|
|
||
|
|
preTransformNestedPredicate(Attrs, Attrs, Rels, Rels, Pred, Pred) :-
|
||
|
|
not(isSubqueryPred(Pred)).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
The SQL predicates EXISTS, NOT EXISTS, ALL and ANY are transformed to a canonical form, which can be further unnested.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
% case operator ~exists~
|
||
|
|
preTransformNestedPredicate(Attrs, Attrs, Rels, Rels,
|
||
|
|
exists(select SubAttr from RelsWhere),
|
||
|
|
0 < (select count(SubAttr) from RelsWhere)).
|
||
|
|
|
||
|
|
% case operator ~not exists~
|
||
|
|
preTransformNestedPredicate(Attrs, Attrs, Rels, Rels,
|
||
|
|
not(exists(select SubAttr from RelsWhere)),
|
||
|
|
0 = (select count(SubAttr) from RelsWhere)).
|
||
|
|
|
||
|
|
% case operator ~any~
|
||
|
|
preTransformNestedPredicate(Attrs, Attrs, Rels, Rels, Pred, NewPred) :-
|
||
|
|
Pred =.. [Op, Attr, any(select SubAttr from RelsWhere)],
|
||
|
|
anyToAggr(Op, Aggr),
|
||
|
|
AggrExpression =.. [Aggr, SubAttr],
|
||
|
|
NewPred =.. [Op, Attr, select AggrExpression from RelsWhere].
|
||
|
|
|
||
|
|
% special handling for ~= any(Query)~
|
||
|
|
preTransformNestedPredicate(Attrs, Attrs, Rels, Rels,
|
||
|
|
Attr = any(Query), Attr in(Query)).
|
||
|
|
|
||
|
|
% special handling for ~<> any(Query)~
|
||
|
|
preTransformNestedPredicate(Attrs, Attrs, Rels, Rels,
|
||
|
|
Attr <> any(Query), Attr not in(Query)).
|
||
|
|
|
||
|
|
% case operator ~all~
|
||
|
|
preTransformNestedPredicate(Attrs, Attrs, Rels, Rels, Pred, NewPred) :-
|
||
|
|
Pred =.. [Op, Attr, all(select SubAttr as Alias from RelsWhere)],
|
||
|
|
allToAggr(Op, Aggr),
|
||
|
|
AggrExpression =.. [Aggr, SubAttr],
|
||
|
|
NewPred =.. [Op, Attr, select AggrExpression as Alias from RelsWhere].
|
||
|
|
|
||
|
|
% case operator ~all~
|
||
|
|
preTransformNestedPredicate(Attrs, Attrs, Rels, Rels, Pred, NewPred) :-
|
||
|
|
Pred =.. [Op, Attr, all(select SubAttr from RelsWhere)],
|
||
|
|
allToAggr(Op, Aggr),
|
||
|
|
AggrExpression =.. [Aggr, SubAttr],
|
||
|
|
NewPred =.. [Op, Attr, select AggrExpression from RelsWhere].
|
||
|
|
|
||
|
|
% default case, no pretransformation
|
||
|
|
preTransformNestedPredicate(Attrs, Attrs, Rels, Rels, Pred, Pred).
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Nested queries are transformed to their canonical form in the attribute list, the relation list and the predicate list.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
transform(Query orderby Order, Query2 orderby Order) :-
|
||
|
|
transform(Query, Query2).
|
||
|
|
|
||
|
|
transform(Query groupby Group, Query2 groupby Group) :-
|
||
|
|
transform(Query, Query2).
|
||
|
|
|
||
|
|
transform(Query first N, Query2 first N) :-
|
||
|
|
transform(Query, Query2).
|
||
|
|
|
||
|
|
transform(Query last N, Query2 last N) :-
|
||
|
|
transform(Query, Query2).
|
||
|
|
|
||
|
|
transform(select Attrs from Rels where Preds,
|
||
|
|
select CanAttrs from CanRels where CanPreds) :-
|
||
|
|
transform(select Attrs from Rels, select Attrs2 from Rels2),
|
||
|
|
transformNestedPredicates(Attrs2, CanAttrs, Rels2,
|
||
|
|
CanRels, Preds, CanPredList),
|
||
|
|
flatten(CanPredList, CanPreds).
|
||
|
|
|
||
|
|
transform(select Attrs from Rels, select CanAttrs from CanRels) :-
|
||
|
|
transformNestedAttributes(Attrs, Attrs2, Rels, Rels2),
|
||
|
|
transformNestedRelations(Attrs2, CanAttrs, Rels2, CanRels).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Default handling for queries without subqueries.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
transform(Query, Query).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Subqueries in the attribute list have to yield a scalar result. If the nested query is uncorrelated with the outer query,
|
||
|
|
it can be evaluated independently of it and replaced by its result.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
transformNestedAttributes([], [], Rels, Rels).
|
||
|
|
|
||
|
|
transformNestedAttributes(Attr, Attr2, Rels, Rels2) :-
|
||
|
|
not(is_list(Attr)),
|
||
|
|
transformNestedAttribute(Attr, Attr2, Rels, Rels2).
|
||
|
|
|
||
|
|
transformNestedAttributes([ Attr | Rest ],
|
||
|
|
[ Attr2 | Rest2 ], Rels, Rels3) :-
|
||
|
|
transformNestedAttribute(Attr, Attr2, Rels, Rels2),
|
||
|
|
transformNestedAttributes(Rest, Rest2, Rels2, Rels3).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Replace a scalar, uncorrelated subquery with its result in the attribute list. As SECONDO does not generate temporary names
|
||
|
|
for constants in the attribute list, renaming has to occurr.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
transformNestedAttribute(Subquery as Variable, Value, Rels, Rels) :-
|
||
|
|
nestingType(Subquery, a),
|
||
|
|
optimize(Subquery, SecondoQuery, _),
|
||
|
|
atom(SecondoQuery),
|
||
|
|
atom_concat('query ', SecondoQuery, QueryText),
|
||
|
|
secondo(QueryText, [_, Result]),
|
||
|
|
not(is_list(Result)),
|
||
|
|
Value =.. [as, Result, Variable].
|
||
|
|
% atom_concat(Result, ' as ', Temp),
|
||
|
|
% atom_concat(Temp, Variable, Value).
|
||
|
|
|
||
|
|
transformNestedAttribute(Attr, Attr, Rels, Rels) :-
|
||
|
|
not(isQuery(Attr)).
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Handling of nested queries in the from clause. Uncorrelated subqueries are transformed
|
||
|
|
into a temporary relation. The resulting temporary relation is inserted into the
|
||
|
|
original query in place of the subquery. Transformation for correlated subqueries will fail.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
transformNestedRelations(Attrs, Attrs, [], []).
|
||
|
|
|
||
|
|
transformNestedRelations(Attrs, Attrs2, Rel, Rel2) :-
|
||
|
|
not(is_list(Rel)),
|
||
|
|
transformNestedRelation(Attrs, Attrs2, Rel, Rel2).
|
||
|
|
|
||
|
|
transformNestedRelations(Attrs, Attrs3,
|
||
|
|
[ Rel | Rest ], [ Rel2 | Rest2]) :-
|
||
|
|
transformNestedRelation(Attrs, Attrs2, Rel, Rel2),
|
||
|
|
transformNestedRelations(Attrs2, Attrs3, Rest, Rest2).
|
||
|
|
|
||
|
|
|
||
|
|
transformNestedRelation(Attrs, Attrs, Query, NewRel) :-
|
||
|
|
transform(Query, CanonicalQuery),
|
||
|
|
isQuery(CanonicalQuery),
|
||
|
|
newTempRel(CanonicalQuery, NewRel).
|
||
|
|
|
||
|
|
transformNestedRelation(Attrs, Attrs, (Query) as _, NewRel) :-
|
||
|
|
transform(Query, CanonicalQuery),
|
||
|
|
isQuery(CanonicalQuery),
|
||
|
|
newTempRel(CanonicalQuery, NewRel).
|
||
|
|
|
||
|
|
transformNestedRelation(Attrs, Attrs, Rel, Rel) :-
|
||
|
|
not(isQuery(Rel)).
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Subqueries in predicates will be transformed to their canonical equivalents by the following algorithm NEST-G
|
||
|
|
|
||
|
|
(1) Transform each type-A predicate to a simple predicate by completely evaluating the subquery. If the subquery itself is
|
||
|
|
nested, algorithm NEST-G is applied recursively on the subquery. When the nested query has been evaluated,
|
||
|
|
it is replaced by its result.
|
||
|
|
(2) Transform each type-JA predicate to an equivalent type-N or type-J subquery by algorithm NEST-JA/NEST-G. If the subquery
|
||
|
|
is further nested, algorithm NEST-G will be invoked recursively on the subquery. The subquery is replaced by the transformed
|
||
|
|
subquery
|
||
|
|
(3) Transform each type-D nested subquery to its canonical form by algorithm NEST-D. If either query of the division predicate
|
||
|
|
is further nested, algorithm NEST-G will be invoked recursively on the subquery. The predicate will be replaced by an appropriate
|
||
|
|
set of join predicates
|
||
|
|
(4) Transform the resulting query, which consists only of type-N and type-J subqueries, to an equivalent canonical query by
|
||
|
|
algorithm NEST-N-J
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
transformNestedPredicates(Attrs, Attrs, Rels, Rels, [], []).
|
||
|
|
|
||
|
|
transformNestedPredicates(Attrs, Attrs2, Rels, Rels2, Pred, Pred2) :-
|
||
|
|
not(is_list(Pred)),
|
||
|
|
transformNestedPredicate(Attrs, Attrs2, Rels, Rels2, Pred, Pred2).
|
||
|
|
|
||
|
|
transformNestedPredicates(Attrs, Attrs3, Rels, Rels3,
|
||
|
|
[ Pred | Rest ], [ Pred2 | Rest2 ]) :-
|
||
|
|
transformNestedPredicate(Attrs, Attrs2, Rels, Rels2, Pred, Pred2),
|
||
|
|
dc(subqueryUnnesting, ( not(Pred = Pred2)
|
||
|
|
-> dm(subqueryUnnesting,
|
||
|
|
['\nPredicate: ', Pred, '\nTransformedPredicate: ', Pred2])
|
||
|
|
; true
|
||
|
|
)),
|
||
|
|
transformNestedPredicates(Attrs2, Attrs3, Rels2, Rels3, Rest, Rest2).
|
||
|
|
|
||
|
|
transformNestedPredicate(Attrs, Attrs, Rels, Rels, Pred, Pred) :-
|
||
|
|
not(isSubqueryPred(Pred)).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
The SQL predicates EXISTS, NOT EXISTS, ALL and ANY are transformed to a canonical form, which can be further unnested.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
% case operator ~exists~
|
||
|
|
transformNestedPredicate(Attrs, Attrs2, Rels, Rels2,
|
||
|
|
exists(select SubAttr from RelsWhere), TransformedQuery) :-
|
||
|
|
transformNestedPredicate(Attrs, Attrs2, Rels, Rels2,
|
||
|
|
0 < (select count(SubAttr) from RelsWhere), TransformedQuery),
|
||
|
|
write_canonical(TransformedQuery).
|
||
|
|
|
||
|
|
% case operator ~not exists~
|
||
|
|
transformNestedPredicate(Attrs, Attrs2, Rels, Rels2,
|
||
|
|
not(exists(select SubAttr from RelsWhere)), TransformedQuery) :-
|
||
|
|
transformNestedPredicate(Attrs, Attrs2, Rels, Rels2,
|
||
|
|
0 = (select count(SubAttr) from RelsWhere), TransformedQuery),
|
||
|
|
write_canonical(TransformedQuery).
|
||
|
|
|
||
|
|
% case operator ~any~
|
||
|
|
transformNestedPredicate(Attrs, Attrs2,
|
||
|
|
Rels, Rels2, Pred, TransformedQuery) :-
|
||
|
|
Pred =.. [Op, Attr, any(select SubAttr from RelsWhere)],
|
||
|
|
anyToAggr(Op, Aggr),
|
||
|
|
AggrExpression =.. [Aggr, SubAttr],
|
||
|
|
NewPred =.. [Op, Attr, select AggrExpression from RelsWhere],
|
||
|
|
transformNestedPredicate(Attrs, Attrs2,
|
||
|
|
Rels, Rels2, NewPred, TransformedQuery),
|
||
|
|
write_canonical(TransformedQuery).
|
||
|
|
|
||
|
|
% special handling for ~= any(Query)~
|
||
|
|
transformNestedPredicate(Attrs, Attrs2, Rels, Rels2,
|
||
|
|
Attr = any(Query), TransformedQuery) :-
|
||
|
|
transformNestedPredicate(Attrs, Attrs2, Rels, Rels2,
|
||
|
|
Attr in(Query), TransformedQuery),
|
||
|
|
write_canonical(TransformedQuery).
|
||
|
|
|
||
|
|
% special handling for ~<> any(Query)~
|
||
|
|
transformNestedPredicate(Attrs, Attrs2, Rels, Rels2,
|
||
|
|
Attr <> any(Query), TransformedQuery) :-
|
||
|
|
transformNestedPredicate(Attrs, Attrs2, Rels, Rels2,
|
||
|
|
Attr not in(Query), TransformedQuery),
|
||
|
|
write_canonical(TransformedQuery).
|
||
|
|
|
||
|
|
% case operator ~all~
|
||
|
|
transformNestedPredicate(Attrs, Attrs2,
|
||
|
|
Rels, Rels2, Pred, TransformedQuery) :-
|
||
|
|
Pred =.. [Op, Attr, all(select SubAttr as Alias from RelsWhere)],
|
||
|
|
allToAggr(Op, Aggr),
|
||
|
|
AggrExpr =.. [Aggr, SubAttr],
|
||
|
|
NewPred =.. [Op, Attr, select AggrExpr as Alias from RelsWhere],
|
||
|
|
transformNestedPredicate(Attrs, Attrs2,
|
||
|
|
Rels, Rels2, NewPred, TransformedQuery),
|
||
|
|
write_canonical(TransformedQuery).
|
||
|
|
|
||
|
|
% case operator ~all~
|
||
|
|
transformNestedPredicate(Attrs, Attrs2,
|
||
|
|
Rels, Rels2, Pred, TransformedQuery) :-
|
||
|
|
Pred =.. [Op, Attr, all(select SubAttr from RelsWhere)],
|
||
|
|
allToAggr(Op, Aggr),
|
||
|
|
AggrExpression =.. [Aggr, SubAttr],
|
||
|
|
NewPred =.. [Op, Attr, select AggrExpression from RelsWhere],
|
||
|
|
transformNestedPredicate(Attrs, Attrs2,
|
||
|
|
Rels, Rels2, NewPred, TransformedQuery),
|
||
|
|
write_canonical(TransformedQuery).
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
The subquery in this predicate does not contain a join predicate that references the relation of the outer query block
|
||
|
|
and has an aggregation function associated with the column name. As the subquery yields a scalar result, which is independent
|
||
|
|
of the outer query, the subqeery will be evaluated and replaced by its result.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
transformNestedPredicate(Attrs, Attrs,
|
||
|
|
Rels, Rels, SubqueryPred, SubqueryPred2) :-
|
||
|
|
SubqueryPred =..[Op, Attr, Subquery],
|
||
|
|
evaluateSubquery(Subquery, Result),
|
||
|
|
SubqueryPred2 =.. [Op, Attr, Result].
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
The subquery in this predicate does not contain a join predicate that references the relation of the outer query block
|
||
|
|
and does not have an aggregation function associated with the column name. Implements algorithm NEST-N-J
|
||
|
|
(1) Combine the from-clause of subquery and outer query into one from-clause
|
||
|
|
(2) Build the conjunction of the where-clauses of inner and outer query into one where-clause
|
||
|
|
(3) Replace the subquery predicate by a corresponding join predicate
|
||
|
|
(4) Retain the select-clause of the outer query
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
% case subquery with predicates
|
||
|
|
transformNestedPredicate(Attrs, Attrs2, Rels, Rels2, Pred, Pred2) :-
|
||
|
|
Pred =.. [Op, Attr, Subquery],
|
||
|
|
transform(Subquery, CanSubquery),
|
||
|
|
CanSubquery =.. [from, Select, Where],
|
||
|
|
Select =.. [select, SubAttr],
|
||
|
|
Where =.. [where | [ CanRels | CanPreds ]] ,
|
||
|
|
(nestingType(CanSubquery, n) ; nestingType(CanSubquery, j)),
|
||
|
|
dm(subqueryUnnesting, ['\nNEST-N-J:\n']),
|
||
|
|
( is_list(SubAttr)
|
||
|
|
-> nth1(1, SubAttr, CanAttr)
|
||
|
|
; SubAttr = CanAttr
|
||
|
|
),
|
||
|
|
restrict(Attrs, Rels, Attrs2),
|
||
|
|
makeList(Rels, RelsList),
|
||
|
|
makeList(CanRels, CanRelsList),
|
||
|
|
retainSetSemantics(RelsList, Attr, Op, CanAttr,
|
||
|
|
CanRelsList, CanPreds, CanRels2, PredList),
|
||
|
|
append(RelsList, CanRels2, Rels2),
|
||
|
|
% subqueryToJoinOp(Op, NewOp),
|
||
|
|
% JoinPredicate =.. [NewOp, Attr, CanAttr],
|
||
|
|
% makeList(CanPreds, CanPredsList),
|
||
|
|
% append([JoinPredicate], CanPredsList, PredList),
|
||
|
|
flatten(PredList, Pred2).
|
||
|
|
|
||
|
|
% case subquery without predicates
|
||
|
|
transformNestedPredicate(Attrs, Attrs2, Rels, Rels2, Pred, JoinPredicate) :-
|
||
|
|
Pred =.. [Op, Attr, Subquery],
|
||
|
|
transform(Subquery, CanSubquery),
|
||
|
|
CanSubquery =.. [from, Select, CanRels],
|
||
|
|
Select =.. [select, SubAttr],
|
||
|
|
(nestingType(CanSubquery, n) ; nestingType(CanSubquery, j)),
|
||
|
|
dm(subqueryUnnesting, ['\nNEST-N-J:\n']),
|
||
|
|
( is_list(SubAttr)
|
||
|
|
-> nth1(1, SubAttr, CanAttr)
|
||
|
|
; SubAttr = CanAttr
|
||
|
|
),
|
||
|
|
restrict(Attrs, Rels, Attrs2),
|
||
|
|
makeList(Rels, RelsList),
|
||
|
|
makeList(CanRels, CanRelsList),
|
||
|
|
retainSetSemantics(RelsList, Attr, Op,
|
||
|
|
CanAttr, CanRelsList, [], CanRels2, JoinPredicate),
|
||
|
|
append(RelsList, CanRels2, Rels2).
|
||
|
|
% subqueryToJoinOp(Op, NewOp),
|
||
|
|
% JoinPredicate =.. [NewOp, Attr, CanAttr].
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Implements Algorithm NEST-JA2 as designed by Ganski, Wong.
|
||
|
|
(1) Project the join column of the outer relation and restrict it with any simple predicates applying to the outer relation
|
||
|
|
(2) Create a temporary relation, joining the inner relation with the projection of the outer relation. If the aggragate function
|
||
|
|
is ~COUNT~, the join must be an outer join, and the inner relation must be restricted and projected before the join is performed.
|
||
|
|
If the aggregate function is ~COUNT([star])~, compute the ~COUNT~ function over the join column. The join predicate must use the same operator
|
||
|
|
as the join predicate in the original query (except that it must be converted to the corresponding outer operator in case of
|
||
|
|
~COUNT~), and the join predicate in the original query must be changed to ~=~. In the select clause, select the join column from
|
||
|
|
the outer table int the join predicate instead of the inner table. The groupby clause will also contain columns from the outer
|
||
|
|
relation
|
||
|
|
(3) Join the outer relation with the temporary relation, according to the transformed version of the original query
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
transformNestedPredicate(Attrs, Attrs2, Rels, Rels2, Pred, Pred2) :-
|
||
|
|
Pred =.. [Op, Attr, Subquery],
|
||
|
|
transform(Subquery, CanonicalSubquery),
|
||
|
|
nestingType(CanonicalSubquery, ja),
|
||
|
|
dm(subqueryUnnesting, ['\nNEST-JA2']),
|
||
|
|
CanonicalSubquery =.. [from, Select, Where],
|
||
|
|
Select =.. [select, AggregatedAttr],
|
||
|
|
dm(subqueryDebug, ['\nAggregatedAttr: ', AggregatedAttr]),
|
||
|
|
Where =.. [where | [CanonicalRels | [CanonicalPreds]]],
|
||
|
|
dm(subqueryDebug, ['\nRels: ', Rels]),
|
||
|
|
dm(subqueryDebug, ['\nCanonicalRels: ', CanonicalRels]),
|
||
|
|
dm(subqueryDebug, ['\nCanonicalPreds: ', CanonicalPreds]),
|
||
|
|
makeList(CanonicalRels, CRList),
|
||
|
|
makeList(Rels, RList),
|
||
|
|
% find Relations which do not appear in from clause of inner query
|
||
|
|
findall(R, (member(R, RList), not(member(R, CRList))), OuterRels),
|
||
|
|
dm(subqueryDebug, ['\nOuterRels: ', OuterRels]),
|
||
|
|
% partition Predicates into simple inner, simple outer and join preds,
|
||
|
|
joinPred(CanonicalRels, OuterRels, CanonicalPreds, JoinPreds,
|
||
|
|
SimpleInnerPreds, SimpleOuterPreds, OuterJoinAttrs),
|
||
|
|
dm(subqueryDebug, ['\nSimpleInnerPreds: ', SimpleInnerPreds]),
|
||
|
|
dm(subqueryDebug, ['\nSimpleOuterPreds: ', SimpleOuterPreds]),
|
||
|
|
dm(subqueryDebug, ['\nJoinPreds: ', JoinPreds]),
|
||
|
|
dm(subqueryDebug, ['\nOuterJoinAttrs: ', OuterJoinAttrs]),
|
||
|
|
% restrict and project outer relation
|
||
|
|
( tempRel1(OuterJoinAttrs, SimpleOuterPreds, OuterRels, TempRel1)
|
||
|
|
; throw(error_SQL(subqueries_transformNestedPredicate::tRel1Error))),
|
||
|
|
% restrict and project inner relation
|
||
|
|
( tempRel2(AggregatedAttr, CanonicalRels, OuterRels, SimpleInnerPreds,
|
||
|
|
JoinPreds, TempRel2)
|
||
|
|
; throw(error_SQL(subqueries_transformNestedPredicate::tRel2Error))),
|
||
|
|
% join tempRel1 and tempRel2, applying aggregation
|
||
|
|
( tempRel3(AggregatedAttr, OuterJoinAttrs, TempRel1, TempRel2,
|
||
|
|
JoinPreds, TempRel3, GroupVar, NewJoinAttr1, NewJoinAttr2)
|
||
|
|
; throw(error_SQL(subqueries_transformNestedPredicate::tRel3Error))),
|
||
|
|
dm(subqueryDebug, ['\nTempRels successful...']),
|
||
|
|
% rename attributes, as aliasing in SECONDO and SECONDO optimizer
|
||
|
|
% is not compatible (Attr_alias vs. alias:Attr)
|
||
|
|
newAlias(Var),
|
||
|
|
alias(Var, GroupVar, AliasedAttr),
|
||
|
|
NewPred =.. [Op, Attr, AliasedAttr],
|
||
|
|
dm(subqueryDebug, ['\nNewPred: ', NewPred]),
|
||
|
|
aliasInternal(NewJoinAttr1, JoinAttr1),
|
||
|
|
aliasInternal(JoinAttr2, NewJoinAttr2),
|
||
|
|
NewJoinPred =.. [=, JoinAttr1, Var:JoinAttr2],
|
||
|
|
dm(subqueryDebug, ['\nNewJoinPred: ', NewJoinPred]),
|
||
|
|
append([NewJoinPred], [NewPred], PredNext),
|
||
|
|
dm(subqueryDebug, ['\nPredNext :', PredNext]),
|
||
|
|
makeList(Rels, RelsList),
|
||
|
|
append(RelsList, [TempRel3 as Var], RelsNext),
|
||
|
|
dm(subqueryDebug, ['\nRelsNext :', RelsNext, '\n']),
|
||
|
|
projectIfNeeded(Attrs, RelsList, Attrs1),
|
||
|
|
transformNestedPredicate(Attrs1, Attrs2,
|
||
|
|
RelsNext, Rels2, PredNext, Pred2).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Project the query result to columns of the given relations, if select-clause is [star].
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
|
||
|
|
projectIfNeeded1(Rel as Var, AttrList) :-
|
||
|
|
!,
|
||
|
|
relation(Rel, Attrs),
|
||
|
|
findall(Var:A, member(A, Attrs), AttrList).
|
||
|
|
|
||
|
|
projectIfNeeded1(Rel, Attrs) :-
|
||
|
|
relation(Rel, Attrs).
|
||
|
|
|
||
|
|
projectIfNeeded(*, [], []).
|
||
|
|
|
||
|
|
projectIfNeeded(*, [Rel | Rels], AttrList) :-
|
||
|
|
projectIfNeeded1(Rel, Attr),
|
||
|
|
projectIfNeeded(*, Rels, Attrs),
|
||
|
|
makeList(Attr, Attr1),
|
||
|
|
append(Attr1, Attrs, AttrList).
|
||
|
|
|
||
|
|
projectIfNeeded(Attrs, _, Attrs).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Translate between optimizer syntax for renaming (using operator ~:~) and
|
||
|
|
executable syntax, which uses operator ~\_~ and postfix notation.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
aliasInternal(ExternalAttr, Attr) :-
|
||
|
|
ground(Attr),
|
||
|
|
Attr = Var:InternalAttr,
|
||
|
|
my_concat_atom([InternalAttr, '_', Var], ExternalAttr).
|
||
|
|
|
||
|
|
aliasInternal(ExternalAttr, InternalAttr) :-
|
||
|
|
ground(ExternalAttr),
|
||
|
|
sub_atom(ExternalAttr, B, _, _, '_'),
|
||
|
|
sub_atom(ExternalAttr, 0, B, _, Attr),
|
||
|
|
B1 is B + 1,
|
||
|
|
sub_atom(ExternalAttr, B1, _, 0, Internal),
|
||
|
|
InternalAttr =.. [(:), Internal, Attr].
|
||
|
|
|
||
|
|
aliasInternal(Attr, Attr).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Retain set semantics for operator ~IN~, otherwise duplicates may appear
|
||
|
|
in the unnested result. To achieve this, we need to create a temporary
|
||
|
|
relation, which is a projection and restriction of the inner relations,
|
||
|
|
containing no duplicates.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
% remove duplicates of inner relations, only for operator ~IN~
|
||
|
|
retainSetSemantics(OuterRels, Attr, in, SelectAttr,
|
||
|
|
InnerRels, InnerPreds, [TempRel], PredList) :-
|
||
|
|
joinPred(InnerRels, OuterRels, InnerPreds, JoinPreds,
|
||
|
|
SimpleInnerPreds, _, OuterAttrs),
|
||
|
|
write('\nJoinPreds: '), write(JoinPreds), nl,
|
||
|
|
( ( findall(Alias,
|
||
|
|
( member(A, OuterAttrs), A =.. [:, Alias, _] ), AliasList),
|
||
|
|
setof(A, member(A, AliasList), AL2) )
|
||
|
|
; AL2 = [] ),
|
||
|
|
% convert aliased attributes to internal ~_~ syntax for all
|
||
|
|
% inner attributes in JoinPreds
|
||
|
|
( ( findall(Pred2, (
|
||
|
|
member(Pred, JoinPreds), member(Al, AL2),
|
||
|
|
aliasExternal(Pred, Pred2, dummy as Al),
|
||
|
|
% only consider aliases which are used in JoinPreds
|
||
|
|
aliasExternal(Pred, TPred2, dummy as $$), Pred2 \= TPred2 ),
|
||
|
|
JoinPreds2 ), setof(JP, member(JP, JoinPreds2), JPList) )
|
||
|
|
; JPList = JoinPreds ),
|
||
|
|
write('JoinPreds2: '), write(JPList), nl,
|
||
|
|
append(InnerRels, OuterRels, Rels),
|
||
|
|
( flatten(JoinPreds, [])
|
||
|
|
-> callLookup(select * from Rels, _)
|
||
|
|
; callLookup(select * from Rels where JoinPreds, _)
|
||
|
|
),
|
||
|
|
setof(Attrs, outerAttrs(InnerRels, Attrs), L),
|
||
|
|
flatten(L, L2),
|
||
|
|
( member(SelectAttr, L2)
|
||
|
|
-> AttrList = L2
|
||
|
|
; append([SelectAttr], L2, AttrList)
|
||
|
|
),
|
||
|
|
% convert aliased attribute in the new join predicate also
|
||
|
|
aliasInternal(CanAttr2, SelectAttr),
|
||
|
|
JoinPredicate =.. [=, Attr, CanAttr2],
|
||
|
|
append([JoinPredicate], JPList, PredList),
|
||
|
|
flatten(SimpleInnerPreds, SIPreds),
|
||
|
|
% write('\nSimpleInnerPreds: '), write(SIPreds), nl,
|
||
|
|
tempRel1(AttrList, SIPreds, InnerRels, TempRel).
|
||
|
|
% write('\nTempRel: '), write(TempRel), nl.
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
% all other operators
|
||
|
|
retainSetSemantics(_, _, _, _,
|
||
|
|
Rels, Preds, Rels, Preds).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
---- joinPred(+InnerRels, +OuterRels, +PredicateList, -JoinPreds,
|
||
|
|
-InnerPreds, -OuterPreds, -OuterAttrs)
|
||
|
|
----
|
||
|
|
|
||
|
|
Partition the predicate list in such a way, that ~InnerPreds~ contains all predicates referring to attributes of relations in
|
||
|
|
~InnerRels~, ~OuterPreds~ contains all predicates refering to attributes of relations in ~OuterRels~ and ~JoinPreds~ contains
|
||
|
|
any remaining predicates.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
joinPred(_, _, [], [], [], [], []).
|
||
|
|
joinPred(InnerRels, OuterRels, [ Pred | Rest ],
|
||
|
|
JoinPreds, InnerPreds, OuterPreds, OuterJoinAttrs) :-
|
||
|
|
joinPred(InnerRels, OuterRels, Pred,
|
||
|
|
JoinPred1, InnerPreds1, OuterPreds1, OuterJoinAttrs1),
|
||
|
|
joinPred(InnerRels, OuterRels, Rest,
|
||
|
|
JoinPred2, InnerPreds2, OuterPreds2, OuterJoinAttrs2),
|
||
|
|
makeList(JoinPred1, JP1List),
|
||
|
|
makeList(JoinPred2, JP2List),
|
||
|
|
append(JP1List, JP2List, JoinPreds),
|
||
|
|
makeList(InnerPreds1, IP1List),
|
||
|
|
makeList(InnerPreds2, IP2List),
|
||
|
|
append(IP1List, IP2List, InnerPreds),
|
||
|
|
makeList(OuterPreds1, OP1List),
|
||
|
|
makeList(OuterPreds2, OP2List),
|
||
|
|
append(OP1List, OP2List, OuterPreds),
|
||
|
|
makeList(OuterJoinAttrs1, OA1List),
|
||
|
|
makeList(OuterJoinAttrs2, OA2List),
|
||
|
|
append(OA1List, OA2List, OuterJoinAttrs).
|
||
|
|
|
||
|
|
joinPred(InnerRels, _, Pred, [], InnerPreds, [], []) :-
|
||
|
|
not(is_list(Pred)),
|
||
|
|
Pred =.. [_ | Args],
|
||
|
|
areAttributesOf(Args, InnerRels),
|
||
|
|
makeList(Pred, InnerPreds).
|
||
|
|
|
||
|
|
joinPred(_, OuterRels, Pred, [], [], OuterPreds, []) :-
|
||
|
|
not(is_list(Pred)),
|
||
|
|
Pred =.. [_ | Args],
|
||
|
|
areAttributesOf(Args, OuterRels),
|
||
|
|
makeList(Pred, OuterPreds).
|
||
|
|
|
||
|
|
joinPred(InnerRels, OuterRels, Pred, [], [Pred], [], []) :-
|
||
|
|
makeList(InnerRels, IRelsList),
|
||
|
|
append(IRelsList, OuterRels, Rels),
|
||
|
|
dm(subqueryDebug,
|
||
|
|
['\njoinPred:\n\t select * from ', Rels,
|
||
|
|
' where ', Pred]),
|
||
|
|
callLookup(select * from Rels where Pred, _),
|
||
|
|
setof(Attrs, outerAttrs(OuterRels, Attrs), L),
|
||
|
|
flatten(L, []).
|
||
|
|
|
||
|
|
joinPred(InnerRels, OuterRels, Pred, [Pred], [], [], OuterAttrs) :-
|
||
|
|
makeList(InnerRels, IRelsList),
|
||
|
|
append(IRelsList, OuterRels, Rels),
|
||
|
|
dm(subqueryDebug,
|
||
|
|
['\njoinPred:\n\t select * from ', Rels,
|
||
|
|
' where ', Pred]),
|
||
|
|
callLookup(select * from Rels where Pred, _),
|
||
|
|
setof(Attrs, outerAttrs(OuterRels, Attrs), L),
|
||
|
|
flatten(L, OuterAttrs),
|
||
|
|
dm(subqueryDebug, ['\nOuterAttrs: ', OuterAttrs]).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Find all query attributes which belong to a Relation in the given query list.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
outerAttrs([], []).
|
||
|
|
|
||
|
|
outerAttrs([Rel | Rest], OuterAttrs) :-
|
||
|
|
outerAttrs1([Rel], RelAttrs),
|
||
|
|
outerAttrs(Rest, RestAttrs),
|
||
|
|
append(RelAttrs, RestAttrs, OuterAttrs).
|
||
|
|
|
||
|
|
outerAttrs1(OuterRels, OuterAttrs) :-
|
||
|
|
setof(Attr, (
|
||
|
|
member(Rel, OuterRels),
|
||
|
|
usedAttr(rel(Rel, *),
|
||
|
|
attr(Attr2, _, _)),
|
||
|
|
dcName2externalName(Attr, Attr2)
|
||
|
|
), OuterAttrs),
|
||
|
|
not(OuterAttrs = []).
|
||
|
|
|
||
|
|
outerAttrs1(OuterRels, OuterAttrs) :-
|
||
|
|
setof(Var:Attr, (
|
||
|
|
member(Rel as Var, OuterRels),
|
||
|
|
usedAttr(rel(Rel, Var),
|
||
|
|
attr(Attr2, _, _)),
|
||
|
|
dcName2externalName(Attr, Attr2)
|
||
|
|
), OuterAttrs),
|
||
|
|
not(OuterAttrs = []).
|
||
|
|
|
||
|
|
outerAttrs1([_], []).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
---- areAttributesOf(AttrList, Rels)
|
||
|
|
----
|
||
|
|
|
||
|
|
Is true if all attributes in ~AttrList~ are attributes of relations in ~Rels~
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
areAttributesOf([], _).
|
||
|
|
|
||
|
|
areAttributesOf(Attr, Rels) :-
|
||
|
|
ground(Attr),
|
||
|
|
not(is_list(Attr)),
|
||
|
|
isAttributeOf(Attr, Rels).
|
||
|
|
|
||
|
|
areAttributesOf([ Attr | Rest ], Rels) :-
|
||
|
|
isAttributeOf(Attr, Rels),
|
||
|
|
areAttributesOf(Rest, Rels).
|
||
|
|
|
||
|
|
% NVK ADDED NR
|
||
|
|
% i don't see where this can happend for nested relations.
|
||
|
|
isAttributeOf(Var:Attr, Rel as Var) :-
|
||
|
|
optimizerOption(nestedRelations),
|
||
|
|
isAttributeOf(Var:Attr, Rel).
|
||
|
|
|
||
|
|
isAttributeOf(Var:Attr, Rel) :-
|
||
|
|
optimizerOption(nestedRelations),
|
||
|
|
atomic(Attr),
|
||
|
|
downcase_atom(Attr, AttrDC),
|
||
|
|
findAttrLists(predicate, _SRCSQID, Var, RelX, AttrDesc),
|
||
|
|
RelX=rel(Rel, _),
|
||
|
|
nrSimpleFindAttribute(AttrDC, AttrDesc, _).
|
||
|
|
|
||
|
|
isAttributeOf(Attr, Rel) :-
|
||
|
|
optimizerOption(nestedRelations),
|
||
|
|
atomic(Attr),
|
||
|
|
downcase_atom(Attr, AttrDC),
|
||
|
|
findAttrLists(predicate, _SRCSQID, *, RelX, AttrDesc),
|
||
|
|
RelX=rel(Rel, *),
|
||
|
|
nrSimpleFindAttribute(AttrDC, AttrDesc, _).
|
||
|
|
% NVK ADDED NR END
|
||
|
|
|
||
|
|
|
||
|
|
isAttributeOf(Alias:Attr, Rel as Alias) :-
|
||
|
|
\+ optimizerOption(nestedRelations), % NVK ADDED NR
|
||
|
|
relation(Rel, List),
|
||
|
|
atomic(Attr),
|
||
|
|
downcase_atom(Attr, DCAttr),
|
||
|
|
member(DCAttr, List).
|
||
|
|
|
||
|
|
isAttributeOf(Attr, Rel) :-
|
||
|
|
\+ optimizerOption(nestedRelations), % NVK ADDED NR
|
||
|
|
atomic(Attr),
|
||
|
|
not(is_list(Rel)),
|
||
|
|
relation(Rel, List),
|
||
|
|
atomic(Attr),
|
||
|
|
downcase_atom(Attr, DCAttr),
|
||
|
|
member(DCAttr, List).
|
||
|
|
|
||
|
|
isAttributeOf(Attr, [ Rel | Rest ]) :-
|
||
|
|
\+ optimizerOption(nestedRelations), % NVK ADDED NR
|
||
|
|
(( relation(Rel, List),
|
||
|
|
atomic(Attr),
|
||
|
|
downcase_atom(Attr, DCAttr),
|
||
|
|
member(DCAttr, List)) ;
|
||
|
|
isAttributeOf(Attr, Rest)).
|
||
|
|
|
||
|
|
isAttributeOf(Attr, [ Rel as Alias | Rest ]) :-
|
||
|
|
\+ optimizerOption(nestedRelations), % NVK ADDED NR
|
||
|
|
(( relation(Rel, List),
|
||
|
|
alias(Alias, UnaliasedAttr, Attr),
|
||
|
|
atomic(UnaliasedAttr),
|
||
|
|
downcase_atom(UnaliasedAttr, DCAttr),
|
||
|
|
member(DCAttr, List)) ;
|
||
|
|
isAttributeOf(Attr, Rest)).
|
||
|
|
|
||
|
|
isAttributeOf(Const, _) :-
|
||
|
|
is_list(Const),
|
||
|
|
catch(my_string_to_list(Const, _), _, fail).
|
||
|
|
|
||
|
|
isAttributeOf(Const, _) :-
|
||
|
|
integer(Const).
|
||
|
|
|
||
|
|
neededRels([], Rels, Rels).
|
||
|
|
|
||
|
|
neededRels(Preds, Rels, NeededRels) :-
|
||
|
|
not(is_list(Preds)),
|
||
|
|
lookupPreds([Preds], [Preds2]),
|
||
|
|
Preds2 =.. [pr | List],
|
||
|
|
findall(R, member(rel(R, *), List), NR),
|
||
|
|
findall(R as V, (member(rel(R, V), List), V \= *), NR2),
|
||
|
|
setof(Rel, (member(Rel, Rels) ; member(Rel, NR) ; member(Rel, NR2)),
|
||
|
|
NeededRels).
|
||
|
|
|
||
|
|
neededRels([Pred | Rest], Rels, NeededRels) :-
|
||
|
|
neededRels(Pred, Rels, NR),
|
||
|
|
neededRels(Rest, NR, NeededRels).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Create a temporary relation which is a projection of Rels to ~JoinAttr~
|
||
|
|
|
||
|
|
*/
|
||
|
|
% case no predicates to apply
|
||
|
|
tempRel1(JoinAttrs, [], OuterRels, TempRel1) :-
|
||
|
|
!,
|
||
|
|
subset(OuterRels, NeededRels),
|
||
|
|
areAttributesOf(JoinAttrs, NeededRels),
|
||
|
|
dm(subqueryDebug, ['\nJoinAttrs: ', JoinAttrs]),
|
||
|
|
dm(subqueryDebug, ['\nNeededRels: ', NeededRels]),
|
||
|
|
ground(NeededRels),
|
||
|
|
!,
|
||
|
|
TemporaryRel1 =.. [from, select distinct JoinAttrs, NeededRels],
|
||
|
|
dm(subqueryUnnesting, ['\nTemporaryRel1: ', TemporaryRel1]),
|
||
|
|
newTempRel(TemporaryRel1, TempRel1).
|
||
|
|
|
||
|
|
% case also apply predicates
|
||
|
|
tempRel1(JoinAttrs, Preds, OuterRels, TempRel1) :-
|
||
|
|
!,
|
||
|
|
subset(OuterRels, NeededRels),
|
||
|
|
areAttributesOf(JoinAttrs, NeededRels),
|
||
|
|
dm(subqueryDebug, ['\nJoinAttrs: ', JoinAttrs]),
|
||
|
|
dm(subqueryDebug, ['\nNeededRels: ', NeededRels]),
|
||
|
|
neededRels(Preds, NeededRels, NeededRels2),
|
||
|
|
ground(NeededRels2),
|
||
|
|
!,
|
||
|
|
TemporaryRel1 =.. [from, select distinct JoinAttrs, where(NeededRels2,
|
||
|
|
Preds)],
|
||
|
|
dm(subqueryUnnesting, ['\nTemporaryRel1: ', TemporaryRel1]),
|
||
|
|
newTempRel(TemporaryRel1, TempRel1).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Create a restriction and projection of ~Rels~ by all predicates supplied.
|
||
|
|
|
||
|
|
*/
|
||
|
|
% case no predicates, only projection
|
||
|
|
tempRel2(AggregatedAttr, Rel, OuterRels, [], JoinPreds, TempRel2) :-
|
||
|
|
makeList(Rel, RelList),
|
||
|
|
aggregationAttrs(AggregatedAttr, Rel, Attr),
|
||
|
|
joinPred(OuterRels, RelList, JoinPreds, _, _, _, Attrs),
|
||
|
|
makeList(Attrs, AttrList),
|
||
|
|
makeList(Attr, AttrList1),
|
||
|
|
( Attr \= *
|
||
|
|
-> append(AttrList, AttrList1, AttrList2)
|
||
|
|
; AttrList2 = AttrList ),
|
||
|
|
setof(A, member(A, AttrList2), AttrList3),
|
||
|
|
TemporaryRel2 =.. [from, select AttrList3, Rel],
|
||
|
|
dm(subqueryUnnesting, ['\nTemporaryRel2: ', TemporaryRel2]),
|
||
|
|
newTempRel(TemporaryRel2, TempRel2).
|
||
|
|
|
||
|
|
% case restrict and project
|
||
|
|
tempRel2(AggregatedAttr, Rels, OuterRels, Preds, JoinPreds, TempRel2) :-
|
||
|
|
makeList(Rels, RelList),
|
||
|
|
Where =.. [where, RelList, Preds],
|
||
|
|
aggregationAttrs(AggregatedAttr, Rels, Attr),
|
||
|
|
joinPred(OuterRels, RelList, JoinPreds, _, _, _, Attrs),
|
||
|
|
makeList(Attrs, AttrList),
|
||
|
|
makeList(Attr, AttrList1),
|
||
|
|
( Attr \= *
|
||
|
|
-> append(AttrList, AttrList1, AttrList2)
|
||
|
|
; AttrList2 = AttrList ),
|
||
|
|
setof(A, member(A, AttrList2), AttrList3),
|
||
|
|
TemporaryRel2 =.. [from, select AttrList3, Where],
|
||
|
|
dm(subqueryUnnesting, ['\nTemporaryRel2: ', TemporaryRel2]),
|
||
|
|
newTempRel(TemporaryRel2, TempRel2).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Create temporary relation which replaces the aggregation operation by its
|
||
|
|
constant result for the corresponding query. If the aggregation operation
|
||
|
|
is ~count~ the query is constructed with an outerjoin. A simple join operation
|
||
|
|
is used otherwise.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
tempRel3(AggregatedAttr, JoinAttrs, TempRel1, TempRel2,
|
||
|
|
JoinPreds, TempRel3, NewColumn, NewJoinAttr1, NewJoinAttr2) :-
|
||
|
|
AggregatedAttr =.. [AggrOp, Attr],
|
||
|
|
not(AggrOp = count),
|
||
|
|
dm(subqueryDebug, ['\nAggrOp: ', AggrOp]),
|
||
|
|
dm(subqueryDebug, ['\nAttr: ', Attr]),
|
||
|
|
newVariable(NewColumn),
|
||
|
|
aliasExternal(Attr, Attr2, TempRel2),
|
||
|
|
dm(subqueryDebug, ['\nAttr2: ', Attr2]),
|
||
|
|
AggregatedAttr2 =.. [AggrOp, Attr2],
|
||
|
|
makeList(AggregatedAttr2 as NewColumn, AggrList),
|
||
|
|
dm(subqueryDebug, ['\nJoinAttrs: ', JoinAttrs]),
|
||
|
|
findall(JoinAttr2,
|
||
|
|
( member(JoinAttr, JoinAttrs),
|
||
|
|
aliasExternal(JoinAttr, JoinAttr2, TempRel2)
|
||
|
|
),
|
||
|
|
JoinAttrs2
|
||
|
|
),
|
||
|
|
dm(subqueryDebug, ['\nJoinAttrs2: ', JoinAttrs2]),
|
||
|
|
append(JoinAttrs2, AggrList, AttrList),
|
||
|
|
findall(Pred2,
|
||
|
|
( member(Pred, JoinPreds),
|
||
|
|
aliasExternal(Pred, Pred2, TempRel2)
|
||
|
|
),
|
||
|
|
JoinPreds2
|
||
|
|
),
|
||
|
|
makeList(TempRel2, TR2List),
|
||
|
|
append([TempRel1], TR2List, Rels),
|
||
|
|
TempRelation3 =..
|
||
|
|
[groupby, from(select AttrList, where(Rels, JoinPreds2)), JoinAttrs2],
|
||
|
|
dm(subqueryDebug, ['\nTemporaryRel3: ', TempRelation3]),
|
||
|
|
rewriteQuery(TempRelation3, RQuery),
|
||
|
|
callLookup(RQuery, Query2), !,
|
||
|
|
queryToPlan(Query2, Plan, _), !,
|
||
|
|
dm(subqueryDebug, ['\nPlan: ', Plan]),
|
||
|
|
findJoinAttrs(Plan, JoinAttr1, JoinAttr2, _),
|
||
|
|
dm(subqueryDebug, ['\nJoinAttr1: ', JoinAttr1, '\nJoinAttr2: ', JoinAttr2]),
|
||
|
|
( isAttributeOf(JoinAttr1, TempRel1)
|
||
|
|
-> ( NewJoinAttr1 = JoinAttr1, NewJoinAttr2 = JoinAttr2 )
|
||
|
|
; ( NewJoinAttr1 = JoinAttr2, NewJoinAttr2 = JoinAttr1 )
|
||
|
|
),
|
||
|
|
append([NewJoinAttr2], AggrList, AttrList2),
|
||
|
|
dm(subqueryDebug, ['\nAttrList2: ', AttrList2]),
|
||
|
|
TemporaryRel3 =..
|
||
|
|
[groupby, from(select AttrList2, where(Rels, JoinPreds2)), NewJoinAttr2],
|
||
|
|
dm(subqueryUnnesting, ['\nTemporaryRel3: ', TemporaryRel3]),
|
||
|
|
newTempRel(TemporaryRel3, TempRel3).
|
||
|
|
|
||
|
|
% case aggregation function = count, use full outerjoin
|
||
|
|
tempRel3(AggregatedAttr, JoinAttrs, TempRel1, TempRel2,
|
||
|
|
JoinPreds, TempRel3, NewColumn, NewJoinAttr1, NewJoinAttr2) :-
|
||
|
|
AggregatedAttr =.. [AggrOp, Attr],
|
||
|
|
AggrOp = count,
|
||
|
|
dm(subqueryDebug, ['\nAggrOp: ', AggrOp]),
|
||
|
|
dm(subqueryDebug, ['\nAttr: ', Attr]),
|
||
|
|
newVariable(NewColumn),
|
||
|
|
aliasExternal(Attr, Attr2, TempRel2),
|
||
|
|
dm(subqueryDebug, ['\nAttr2: ', Attr2]),
|
||
|
|
AggregatedAttr2 =.. [AggrOp, Attr2],
|
||
|
|
makeList(AggregatedAttr2 as NewColumn, AggrList),
|
||
|
|
dm(subqueryDebug, ['\nJoinAttrs: ', JoinAttrs]),
|
||
|
|
findall(JoinAttr2,
|
||
|
|
( member(JoinAttr, JoinAttrs),
|
||
|
|
aliasExternal(JoinAttr, JoinAttr2, TempRel2)
|
||
|
|
),
|
||
|
|
JoinAttrs2
|
||
|
|
),
|
||
|
|
dm(subqueryDebug, ['\nJoinAttrs2: ', JoinAttrs2]),
|
||
|
|
append(JoinAttrs2, AggrList, AttrList),
|
||
|
|
findall(Pred2,
|
||
|
|
( member(Pred, JoinPreds),
|
||
|
|
aliasExternal(Pred, Pred2, TempRel2)
|
||
|
|
),
|
||
|
|
JoinPreds2
|
||
|
|
),
|
||
|
|
makeList(TempRel2, TR2List),
|
||
|
|
append([TempRel1], TR2List, Rels),
|
||
|
|
TemporaryRel3 =..
|
||
|
|
[groupby, from(select AttrList, where(Rels, JoinPreds2)), JoinAttrs2],
|
||
|
|
dm(subqueryDebug, ['\nTemporaryRel3: ', TemporaryRel3]),
|
||
|
|
rewriteQuery(TemporaryRel3, RQuery),
|
||
|
|
callLookup(RQuery, Query2), !,
|
||
|
|
queryToPlan(Query2, Plan, _), !,
|
||
|
|
dm(subqueryDebug, ['\nPlan: ', Plan]),
|
||
|
|
findJoinAttrs(Plan, JoinAttr1, JoinAttr2, Op),
|
||
|
|
dm(subqueryDebug, ['\nJoinAttr1: ', JoinAttr1, '\nJoinAttr2: ', JoinAttr2]),
|
||
|
|
( isAttributeOf(JoinAttr1, TempRel1)
|
||
|
|
-> OuterJoinPred = outerjoin(Op, attrname(JoinAttr1), attrname(JoinAttr2))
|
||
|
|
; ( OuterJoinPred = outerjoin(Op, attrname(JoinAttr2), attrname(JoinAttr1)),
|
||
|
|
retractall(outerjoinCommuted),
|
||
|
|
assert(outerjoinCommuted))
|
||
|
|
),
|
||
|
|
OuterJoinPred =..
|
||
|
|
[outerjoin, Op, attrname(NewJoinAttr1), attrname(NewJoinAttr2)],
|
||
|
|
dm(subqueryDebug, ['\nOuterJoinPred: ', OuterJoinPred]),
|
||
|
|
newQuery,
|
||
|
|
lookupRel(TempRel1, IntTempRel1),
|
||
|
|
dm(subqueryDebug, ['\nIntTempRel1: ', IntTempRel1]),
|
||
|
|
lookupRel(TempRel2, IntTempRel2),
|
||
|
|
dm(subqueryDebug, ['\nIntTempRel2: ', IntTempRel2]),
|
||
|
|
lookupAttr(JoinAttr1 as NewColumn, _ as IntNewColumn),
|
||
|
|
dm(subqueryDebug, ['\nIntNewColumn: ', IntNewColumn]),
|
||
|
|
% lookupPred(OuterJoinPred,
|
||
|
|
% pr(outerjoin(IntJoinAttr1, IntJoinAttr2), _, _)),
|
||
|
|
% dm(subqueryDebug, ['\nIntJoinAttr1: ', IntJoinAttr1]),
|
||
|
|
% dm(subqueryDebug, ['\nIntJoinAttr2: ', IntJoinAttr2]),
|
||
|
|
lookupPred(OuterJoinPred, pr(IntOuterJoinPred, _, _)),
|
||
|
|
IntOuterJoinPred =.. [outerjoin, Op, IntJoinAttr1, IntJoinAttr2],
|
||
|
|
makeStream(IntTempRel1, IntStreamRel1),
|
||
|
|
plan_to_atom(IntStreamRel1, ExtTempRel1),
|
||
|
|
dm(subqueryDebug, ['\nExtTempRel1: ', ExtTempRel1]),
|
||
|
|
makeStream(IntTempRel2, IntStreamRel2),
|
||
|
|
plan_to_atom(IntStreamRel2, ExtTempRel2),
|
||
|
|
dm(subqueryDebug, ['\nExtTempRel2: ', ExtTempRel2]),
|
||
|
|
plan_to_atom(IntJoinAttr1, ExtJoinAttr1),
|
||
|
|
dm(subqueryDebug, ['\nExtJoinAttr1: ', ExtJoinAttr1]),
|
||
|
|
plan_to_atom(IntJoinAttr2, ExtJoinAttr2),
|
||
|
|
dm(subqueryDebug, ['\nExtJoinAttr2: ', ExtJoinAttr2]),
|
||
|
|
plan_to_atom(attrname(IntNewColumn), ExtNewColumn),
|
||
|
|
dm(subqueryDebug, ['\nExtNewColumn: ', ExtNewColumn]),
|
||
|
|
plan_to_atom(IntOuterJoinPred, ExtOuterJoinPred),
|
||
|
|
dm(subqueryDebug, ['\nExtOuterJoinPred: ', ExtOuterJoinPred]),
|
||
|
|
my_concat_atom([
|
||
|
|
ExtTempRel1,
|
||
|
|
ExtTempRel2,
|
||
|
|
% ' smouterjoin[',ExtJoinAttr1, ',', ExtJoinAttr2, ']',
|
||
|
|
ExtOuterJoinPred,
|
||
|
|
' sortby[', ExtJoinAttr1, ' asc]',
|
||
|
|
' groupby[', ExtJoinAttr1, ';', ExtNewColumn,
|
||
|
|
': group feed filter[not(isempty(.', ExtJoinAttr2, ' ))] count]',
|
||
|
|
' projectextend[', ExtNewColumn, '; ', ExtJoinAttr2 ,
|
||
|
|
': .', ExtJoinAttr1, ']',
|
||
|
|
' consume'],
|
||
|
|
'', TempRelation3),
|
||
|
|
dm(subqueryUnnesting, ['\nTempRelation3: ', TempRelation3]),
|
||
|
|
( newTempRel_direct(TempRelation3, TempRel3)
|
||
|
|
-> true
|
||
|
|
; throw(error_SQL(subqueries_tempRel3::errorInQuery))).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Get all attributes of a list of attribut expressions.
|
||
|
|
|
||
|
|
*/
|
||
|
|
aggregationAttrs(AggrExpr, Rels, AttrList2) :-
|
||
|
|
AggrExpr =.. [_, Term],
|
||
|
|
aggregationAttrs1(Term, Rels, AttrList),
|
||
|
|
flatten(AttrList, AttrList2).
|
||
|
|
|
||
|
|
aggregationAttrs1([], _, []).
|
||
|
|
|
||
|
|
aggregationAttrs1(Attr, Rels, Attr) :-
|
||
|
|
not(is_list(Attr)),
|
||
|
|
isAttributeOf(Attr, Rels),
|
||
|
|
not(integer(Attr)).
|
||
|
|
|
||
|
|
aggregationAttrs1([ Term | Rest ], Rels, [Attr | AttrList]) :-
|
||
|
|
aggregationAttrs1(Term, Rels, Attr),
|
||
|
|
aggregationAttrs1(Rest, Rels, AttrList).
|
||
|
|
|
||
|
|
aggregationAttrs1(Term, Rels, AttrList) :-
|
||
|
|
not(is_list(Term)),
|
||
|
|
compound(Term),
|
||
|
|
Term =.. [Op | Args],
|
||
|
|
Op \= (:),
|
||
|
|
aggregationAttrs1(Args, Rels, AttrList).
|
||
|
|
|
||
|
|
aggregationAttrs1(Term, _, []) :-
|
||
|
|
not(is_list(Term)).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Ugly hack to find the join Attributes which the optimizer would select on a Join Query with the same predicates. Used only to select
|
||
|
|
which attributes will be used in the outerjoin.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
% case symmjoin as join operator
|
||
|
|
findJoinAttrs(Plan, JoinAttr1, JoinAttr2, Op) :-
|
||
|
|
Plan =.. [symmjoin | Args], !,
|
||
|
|
nth1(3, Args, Pred),
|
||
|
|
dm(subqueryDebug, ['\nPred: ', Pred]),
|
||
|
|
Pred =.. [Op, attr(Attr1, _, _), attr(Attr2, _, _)],
|
||
|
|
( Attr1 = Var1:AttrName1 ; Attr1 = AttrName1 ),
|
||
|
|
( Attr2 = Var2:AttrName2 ; Attr2 = AttrName2 ),
|
||
|
|
dcName2externalName(JoinAttrName1, AttrName1),
|
||
|
|
dcName2externalName(JoinAttrName2, AttrName2),
|
||
|
|
( (ground(Var1), JoinAttr1 = Var1:JoinAttrName1)
|
||
|
|
; JoinAttr1 = JoinAttrName1 ),
|
||
|
|
( (ground(Var2), JoinAttr2 = Var2:JoinAttrName2)
|
||
|
|
; JoinAttr2 = JoinAttrName2 ).
|
||
|
|
|
||
|
|
% other join operators, assumes that all join operators
|
||
|
|
% end in 'join'
|
||
|
|
findJoinAttrs(Plan, JoinAttr1, JoinAttr2, =) :-
|
||
|
|
Plan =.. [Op | Args],
|
||
|
|
atom_concat(_, 'join', Op), !,
|
||
|
|
nth1(3, Args, attrname(attr(Attr1, _, _))),
|
||
|
|
nth1(4, Args, attrname(attr(Attr2, _, _))),
|
||
|
|
( Attr1 = Var1:AttrName1 ; Attr1 = AttrName1 ),
|
||
|
|
( Attr2 = Var2:AttrName2 ; Attr2 = AttrName2 ),
|
||
|
|
dcName2externalName(JoinAttrName1, AttrName1),
|
||
|
|
dcName2externalName(JoinAttrName2, AttrName2),
|
||
|
|
( (ground(Var1), JoinAttr1 = Var1:JoinAttrName1)
|
||
|
|
; JoinAttr1 = JoinAttrName1 ),
|
||
|
|
( (ground(Var2), JoinAttr2 = Var2:JoinAttrName2)
|
||
|
|
; JoinAttr2 = JoinAttrName2 ).
|
||
|
|
|
||
|
|
findJoinAttrs(Plan, JoinAttr1, JoinAttr2, Op) :-
|
||
|
|
not(is_list(Plan)),
|
||
|
|
compound(Plan),
|
||
|
|
Plan =.. [_ | Args],
|
||
|
|
findJoinAttrs(Args, JoinAttr1, JoinAttr2, Op).
|
||
|
|
|
||
|
|
findJoinAttrs([ Arg ], JoinAttr1, JoinAttr2, Op) :-
|
||
|
|
findJoinAttrs(Arg, JoinAttr1, JoinAttr2, Op).
|
||
|
|
|
||
|
|
findJoinAttrs([ Arg | Rest ], JoinAttr1, JoinAttr2, Op) :-
|
||
|
|
( findJoinAttrs(Arg, JoinAttr1, JoinAttr2, Op) ;
|
||
|
|
( not(Rest = []),
|
||
|
|
findJoinAttrs(Rest, JoinAttr1, JoinAttr2, Op) )).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Translate aliased expression from optimizer to kernel syntax.
|
||
|
|
|
||
|
|
*/
|
||
|
|
aliasExternal(Expr, Expr, TempRel2) :-
|
||
|
|
is_list(TempRel2).
|
||
|
|
|
||
|
|
aliasExternal(Var:Attr, Var:Attr, _ as Var) :-
|
||
|
|
!.
|
||
|
|
|
||
|
|
aliasExternal(Var:Attr, AliasedAttr, T) :-
|
||
|
|
not(is_list(T)),
|
||
|
|
my_concat_atom([Attr, '_', Var], '', AliasedAttr).
|
||
|
|
|
||
|
|
aliasExternal(Attr, Attr, _) :-
|
||
|
|
atomic(Attr).
|
||
|
|
|
||
|
|
aliasExternal(Pred, AliasedPred, T) :-
|
||
|
|
compound(Pred),
|
||
|
|
Pred =.. [Op, Attr1, Attr2],
|
||
|
|
not(Op = (:)),
|
||
|
|
aliasExternal(Attr1, AliasedAttr1, T),
|
||
|
|
aliasExternal(Attr2, AliasedAttr2, T),
|
||
|
|
AliasedPred =.. [Op, AliasedAttr1, AliasedAttr2].
|
||
|
|
|
||
|
|
aliasExternal(Pred, AliasedPred, T) :-
|
||
|
|
compound(Pred),
|
||
|
|
Pred =.. [UnaryOp, Pred2],
|
||
|
|
aliasExternal(Pred2, AliasedPred2, T),
|
||
|
|
AliasedPred =..[UnaryOp, AliasedPred2].
|
||
|
|
|
||
|
|
aliasExternal(Expr, AliasedExpr, T) :-
|
||
|
|
compound(Expr),
|
||
|
|
Expr =.. [Op, Arg1, Arg2, Arg3],
|
||
|
|
not(Op = (:)),
|
||
|
|
aliasExternal(Arg1, AliasedArg1, T),
|
||
|
|
aliasExternal(Arg2, AliasedArg2, T),
|
||
|
|
aliasExternal(Arg3, AliasedArg3, T),
|
||
|
|
AliasedExpr =.. [Op, AliasedArg1, AliasedArg2, AliasedArg3].
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Restrict StarQueries to only select attributes of the given relations
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
restrict(*, Rels, AttrList) :-
|
||
|
|
not(is_list(Rels)),
|
||
|
|
relation(Rels, AttrList).
|
||
|
|
|
||
|
|
restrict(*, Rel as Alias, AttrList2) :-
|
||
|
|
restrict(*, Rel, AttrList),
|
||
|
|
maplist(alias(Alias), AttrList, AttrList2).
|
||
|
|
|
||
|
|
restrict(*, [ Rel | Rest ], AttrList) :-
|
||
|
|
restrict(*, Rel, Attrs),
|
||
|
|
restrict(*, Rest, Attrs2),
|
||
|
|
append(Attrs, Attrs2, AttrList).
|
||
|
|
|
||
|
|
restrict(*, [], []).
|
||
|
|
|
||
|
|
restrict(Attrs, _, Attrs).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
---- alias(?Alias, ?Attr, ?Alias:Attr)
|
||
|
|
----
|
||
|
|
|
||
|
|
Helper predicate to alias/un-alias attribute names.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
alias(_, *, *).
|
||
|
|
|
||
|
|
alias(_, Const, Const) :-
|
||
|
|
integer(Const).
|
||
|
|
|
||
|
|
alias(Alias, Attr, Alias:Attr).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Utitility predicates to define unique names with a defined prefix.
|
||
|
|
|
||
|
|
*/
|
||
|
|
:- dynamic(relDefined/1).
|
||
|
|
:- dynamic(uvarDefined/2).
|
||
|
|
|
||
|
|
newUniqueVar(Name, Var) :-
|
||
|
|
ground(Name),
|
||
|
|
uvarDefined(Name, N),
|
||
|
|
!,
|
||
|
|
N1 is N + 1,
|
||
|
|
retract(uvarDefined(Name, N)),
|
||
|
|
assert(uvarDefined(Name, N1)),
|
||
|
|
atom_concat(Name, N1, Var).
|
||
|
|
|
||
|
|
newUniqueVar(Name, Var) :-
|
||
|
|
ground(Name),
|
||
|
|
assert(uvarDefined(Name, 1)),
|
||
|
|
atom_concat(Name, '1', Var).
|
||
|
|
|
||
|
|
% unique temporary relation name
|
||
|
|
newTempRel(Var) :-
|
||
|
|
!,
|
||
|
|
newUniqueVar('trelxx', Var).
|
||
|
|
|
||
|
|
% uniquey alias name for renaming
|
||
|
|
newAlias(Var) :-
|
||
|
|
\+ optimizerOption(nestedRelations), % NVK ADDED NR
|
||
|
|
!,
|
||
|
|
newUniqueVar('alias', Var).
|
||
|
|
|
||
|
|
/*
|
||
|
|
NVK ADDED NR
|
||
|
|
The current alias is stored here to have access to this value within
|
||
|
|
the plan\_to\_atom phase.
|
||
|
|
|
||
|
|
*/
|
||
|
|
newAlias(Var) :-
|
||
|
|
optimizerOption(nestedRelations),
|
||
|
|
!,
|
||
|
|
getSubqueryCurrent(SQID),
|
||
|
|
aliasBySQID(SQID, Var).
|
||
|
|
% NVK ADDED NR END
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
---- newTempRel(+Query, -TempRelName)
|
||
|
|
----
|
||
|
|
|
||
|
|
Store all temporary Relations created by the evaluation of a subquery for reuse in subsequent invocations.
|
||
|
|
|
||
|
|
---- temporaryRelation(TempRelName, RelQuery, Cost)
|
||
|
|
----
|
||
|
|
Store temporary relation for creation if the optimizer decides on an execution plan involving a temporary Relation.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
|
||
|
|
:- dynamic temporaryRelation/1,
|
||
|
|
temporaryRelation/2.
|
||
|
|
|
||
|
|
newTempRel(Query, TempRelName) :-
|
||
|
|
( temporaryRelation(TempRelName, Query)
|
||
|
|
; ( newTempRel(TempRelName),
|
||
|
|
assert(temporaryRelation(TempRelName, Query)),
|
||
|
|
createTempRel(TempRelName)
|
||
|
|
)
|
||
|
|
),
|
||
|
|
dm(temprels, ['\nTempRelName: ', TempRelName, '\n']).
|
||
|
|
|
||
|
|
% case executable syntax for temprel supplied
|
||
|
|
newTempRel_direct(Plan, TempRelName) :-
|
||
|
|
( temporaryRelation(TempRelName, Plan)
|
||
|
|
; ( newTempRel(TempRelName),
|
||
|
|
my_concat_atom([TempRelName, ' = ', Plan], Query),
|
||
|
|
dm(subqueryDebug, ['\nTempRelDirect Plan: ', Query]),
|
||
|
|
let(Query),
|
||
|
|
assert(temporaryRelation(TempRelName, Plan))
|
||
|
|
)
|
||
|
|
),
|
||
|
|
dm(temprels, ['\nTempRelName_direct: ', TempRelName, '\n']).
|
||
|
|
|
||
|
|
createTempRel(TempRelName) :-
|
||
|
|
ground(TempRelName),
|
||
|
|
temporaryRelation(TempRelName, RelQuery),
|
||
|
|
dm(temprels, ['\nRelQuery: ', RelQuery]),
|
||
|
|
let(TempRelName, RelQuery),
|
||
|
|
retractall(temporaryRelation(TempRelName, _, _)),
|
||
|
|
assert(temporaryRelation(TempRelName)).
|
||
|
|
|
||
|
|
deleteTempRels :-
|
||
|
|
findall(Rel, temporaryRelation(Rel), L),
|
||
|
|
catch(deleteTempRels(L), _, true),
|
||
|
|
retractall(temporaryRelation(_)).
|
||
|
|
|
||
|
|
deleteTempRels([]) :-
|
||
|
|
retractall(relDefined(_)),
|
||
|
|
retractall(temporaryRelation(_)),
|
||
|
|
retractall(temporaryRelation(_, _)).
|
||
|
|
|
||
|
|
deleteTempRels([ Rel | Rest ]) :-
|
||
|
|
dm(temprels, ['\nDeleting temporary Relation ', Rel, ' ...']),
|
||
|
|
catch(drop_relation(Rel), Ex, true),
|
||
|
|
dm(temprels, [Ex]),
|
||
|
|
deleteTempRels(Rest).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Remove all temporary relations in the open database. Will always be called
|
||
|
|
on opening a database to provide a clean execution environment.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
dropTempRels :-
|
||
|
|
retractall(temporaryRelation(_)),
|
||
|
|
retractall(temporaryRelation(_, _)),
|
||
|
|
retractall(rewriteCache(_, _)),
|
||
|
|
findall(Rel, ( databaseName(DB),
|
||
|
|
storedRel(DB, Rel, _),
|
||
|
|
atom_concat('trelxx', _, Rel),
|
||
|
|
not(atom_concat(_, '_sample_s', Rel)),
|
||
|
|
not(atom_concat(_, '_sample_j', Rel))
|
||
|
|
), RelList),
|
||
|
|
not(RelList = []),
|
||
|
|
write_list(['\nINFO:\tRemoving leftover temporary relations...']), nl,
|
||
|
|
catch(deleteTempRels(RelList), _, true).
|
||
|
|
% updateCatalog.
|
||
|
|
|
||
|
|
dropTempRels.
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
type-A nesting, uncorrelated subquery with scalar result.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
nestingType(Subquery, a) :-
|
||
|
|
aggrQuery(Subquery, _, _, _),
|
||
|
|
catch(callLookup(Subquery, _), _, fail),
|
||
|
|
dm(subqueryUnnesting, ['\nnesting Type-A']),
|
||
|
|
!.
|
||
|
|
|
||
|
|
nestingType(Subquery, a) :-
|
||
|
|
userDefAggrQuery(Subquery, _, _, _, _),
|
||
|
|
catch(callLookup(Subquery, _), _, fail),
|
||
|
|
dm(subqueryUnnesting, ['\nnesting Type-A']),
|
||
|
|
!.
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
type-JA nesting, correlated subquery with aggregation function, scalar result.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
nestingType(Subquery, ja) :-
|
||
|
|
aggrQuery(Subquery, _, _, _),
|
||
|
|
dm(subqueryUnnesting, ['\nnesting Type-JA']),
|
||
|
|
!.
|
||
|
|
|
||
|
|
nestingType(Subquery, ja) :-
|
||
|
|
userDefAggrQuery(Subquery, _, _, _, _),
|
||
|
|
dm(subqueryUnnesting, ['\nnesting Type-JA']),
|
||
|
|
!.
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
type-N nesting, uncorrelated subquery with row result
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
nestingType(Subquery, n) :-
|
||
|
|
not(userDefAggrQuery(Subquery , _, _, _, _)),
|
||
|
|
not(aggrQuery(Subquery, _, _, _)),
|
||
|
|
catch(callLookup(Subquery, _), _, fail),
|
||
|
|
dm(subqueryUnnesting, ['\nnesting Type-N']),
|
||
|
|
!.
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
type-J nesting, correlated subquery without aggregation function, row result
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
nestingType(Subquery, j) :-
|
||
|
|
not(userDefAggrQuery(Subquery, _, _, _, _)),
|
||
|
|
not(aggrQuery(Subquery, _, _, _)),
|
||
|
|
dm(subqueryUnnesting, ['\nnesting Type-J']),
|
||
|
|
!.
|
||
|
|
|
||
|
|
nestingType(_, unknown) :-
|
||
|
|
throw(error_SQL(subqueries_nestingType::unknownNesting)).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
18.1.2 Lookup of subquery predicates
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
lookupSubquery(all(Query), all(Query2)) :-
|
||
|
|
lookupSubquery(Query, Query2).
|
||
|
|
|
||
|
|
lookupSubquery(any(Query), any(Query2)) :-
|
||
|
|
lookupSubquery(Query, Query2).
|
||
|
|
|
||
|
|
lookupSubquery(select Attrs from Rels where Preds,
|
||
|
|
select Attrs2 from Rels2List where Preds2List) :-
|
||
|
|
nrAssignAlias, % NVK ADDED NR
|
||
|
|
lookupRelsDblCheck(Rels, Rels2),
|
||
|
|
!,
|
||
|
|
lookupAttrs(Attrs, Attrs2),
|
||
|
|
lookupPreds(Preds, Preds2),
|
||
|
|
makeList(Rels2, Rels2List),
|
||
|
|
makeList(Preds2, Preds2List),
|
||
|
|
(optimizerOption(entropy)
|
||
|
|
-> registerSelfJoins(Preds2List, 1); true).
|
||
|
|
% needed for entropy optimizer
|
||
|
|
|
||
|
|
lookupSubquery(select Attrs from Rels,
|
||
|
|
select Attrs2 from Rels2) :-
|
||
|
|
nrAssignAlias, % NVK ADDED NR
|
||
|
|
lookupRelsDblCheck(Rels, Rels2), !,
|
||
|
|
lookupAttrs(Attrs, Attrs2).
|
||
|
|
|
||
|
|
lookupSubquery(Query orderby Attrs, Query2 orderby Attrs3) :-
|
||
|
|
lookupSubquery(Query, Query2),
|
||
|
|
makeList(Attrs, Attrs2),
|
||
|
|
lookupAttrs(Attrs2, Attrs3).
|
||
|
|
|
||
|
|
lookupSubquery(Query groupby Attrs, Query2 groupby Attrs3) :-
|
||
|
|
lookupSubquery(Query, Query2),
|
||
|
|
makeList(Attrs, Attrs2),
|
||
|
|
lookupAttrs(Attrs2, Attrs3).
|
||
|
|
|
||
|
|
lookupSubquery(Query first N, Query2 first N) :-
|
||
|
|
lookupSubquery(Query, Query2).
|
||
|
|
|
||
|
|
lookupSubquery(Query last N, Query2 last N) :-
|
||
|
|
lookupSubquery(Query, Query2).
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Lookup relation, special error message for subqueries, if relation names
|
||
|
|
are not unique.
|
||
|
|
|
||
|
|
*/
|
||
|
|
lookupRelsDblCheck([], []).
|
||
|
|
|
||
|
|
lookupRelsDblCheck([R | Rs], [R2 | R2s]) :-
|
||
|
|
lookupRelDblCheck(R, R2),
|
||
|
|
lookupRelsDblCheck(Rs, R2s).
|
||
|
|
|
||
|
|
lookupRelsDblCheck(Rel, Rel2) :-
|
||
|
|
not(is_list(Rel)),
|
||
|
|
lookupRelDblCheck(Rel, Rel2).
|
||
|
|
|
||
|
|
lookupRelDblCheck(Rel as Var, rel(RelDC, Var)) :-
|
||
|
|
lookupRel(Rel as Var, rel(RelDC, Var)).
|
||
|
|
|
||
|
|
lookupRelDblCheck(Rel, rel(RelDC, *)) :-
|
||
|
|
not(queryRel(Rel, _)),
|
||
|
|
lookupRel(Rel, rel(RelDC, *)).
|
||
|
|
|
||
|
|
lookupRelDblCheck(Rel, rel(RelDC, *)) :-
|
||
|
|
queryRel(Rel, rel(RelDC, *)),
|
||
|
|
term_to_atom(Rel, RelA),
|
||
|
|
my_concat_atom(['Ambiguous use of relation ',RelA,
|
||
|
|
' in outer and inner query block.'],'',ErrMsg),
|
||
|
|
write_list(['\nERROR:\t',ErrMsg]),
|
||
|
|
throw(
|
||
|
|
error_SQL(subqueries_lookupRelDblCheck(Rel)::malformedExpression::ErrMsg)).
|
||
|
|
|
||
|
|
:- multifile(lookupRelNoDblCheck/2).
|
||
|
|
|
||
|
|
lookupRelNoDblCheck(Rel as Var, rel(RelDC, Var)) :-
|
||
|
|
atomic(Rel), %% changed code FIXME
|
||
|
|
atomic(Var), %% changed code FIXME
|
||
|
|
dcName2externalName(RelDC,Rel),
|
||
|
|
relation(RelDC, _), !, %% changed code FIXME
|
||
|
|
( variable(Var, _)
|
||
|
|
; assert(variable(Var, rel(RelDC, Var)))
|
||
|
|
).
|
||
|
|
|
||
|
|
:- dynamic(currentAttrs/1).
|
||
|
|
:- dynamic(currentRels/1).
|
||
|
|
:- dynamic(currentVariables/1).
|
||
|
|
:- dynamic(isJoinPred/1).
|
||
|
|
:- dynamic(selectivityQuery/1).
|
||
|
|
:- dynamic(selectivityRels/1).
|
||
|
|
:- dynamic(sampleSize/1).
|
||
|
|
:- dynamic(maxSampleCard/1).
|
||
|
|
:- dynamic(maxSelCard/1).
|
||
|
|
:- dynamic(outerjoinCommuted/0).
|
||
|
|
|
||
|
|
|
||
|
|
subquerySelectivity(Pred, [Rel]) :-
|
||
|
|
subquerySelectivity(pr(Pred, Rel)).
|
||
|
|
|
||
|
|
subquerySelectivity(Pred, [Rel1, Rel2]) :-
|
||
|
|
subquerySelectivity(pr(Pred, Rel1, Rel2)).
|
||
|
|
|
||
|
|
relsAfter(Rels, AttrRelsAfter, RelsAfter) :-
|
||
|
|
findall(Rel, ( member(Rel, Rels), not(member(Rel, AttrRelsAfter))), L1),
|
||
|
|
setof(R, member(R, L1), L), append(AttrRelsAfter, L, RelsAfter).
|
||
|
|
|
||
|
|
relsAfter(Rels, [], RelsAfter) :-
|
||
|
|
setof(R, member(R, Rels), RelsAfter).
|
||
|
|
|
||
|
|
relsAfter(Rels, RelsAfter, RelsAfter) :-
|
||
|
|
findall(Rel, ( member(Rel, Rels), not(member(Rel, RelsAfter))), []).
|
||
|
|
|
||
|
|
relsAfter(_, _, _) :-
|
||
|
|
currentRels(QueryRels),
|
||
|
|
currentVariables(QueryVariables),
|
||
|
|
% write('\nQueryRels: '), write(QueryRels), nl,
|
||
|
|
findall(A, variable(A, _), _),
|
||
|
|
% write('\nVariables: '), write(L1), nl,
|
||
|
|
findall([R, rel(R, Var)],
|
||
|
|
( queryRel(R, rel(R, Var)),
|
||
|
|
not(member([R, rel(R, Var)], QueryRels)
|
||
|
|
),
|
||
|
|
retractall(queryRel(R, rel(R, Var)))),
|
||
|
|
_),
|
||
|
|
findall(V,
|
||
|
|
( variable(V, _),
|
||
|
|
not(member(V, QueryVariables)),
|
||
|
|
retractall(variable(V, _))
|
||
|
|
),
|
||
|
|
_),
|
||
|
|
% write('\nRetractRels: '), write(L),
|
||
|
|
% retractall(currentRels(_)),
|
||
|
|
fail.
|
||
|
|
|
||
|
|
% lookup for outerjoin expression
|
||
|
|
lookupSubqueryPred(outerjoin(Op, A1, A2), outerjoin(Op, Attr1, Attr2),
|
||
|
|
RelsBefore, RelsAfter) :-
|
||
|
|
lookupPred1(A1, Attr1, RelsBefore, Attr1RelsAfter),
|
||
|
|
lookupPred1(A2, Attr2, Attr1RelsAfter, RelsAfter),
|
||
|
|
!.
|
||
|
|
|
||
|
|
% case operator ~not in~
|
||
|
|
lookupSubqueryPred(Pred, Pred2, RelsBefore, RelsAfter) :-
|
||
|
|
isSubqueryPred1(Pred),
|
||
|
|
dm(subqueryDebug, ['\nlookupSubqueryPred 1\nPred: ', Pred]),
|
||
|
|
Pred =.. [not, Attr, in(Query)],
|
||
|
|
dm(subqueryDebug,
|
||
|
|
['\nAttr: ', Attr,
|
||
|
|
'\nQuery: ', Query]),
|
||
|
|
lookupPred1(Attr, Attr2, RelsBefore, AttrRelsAfter),
|
||
|
|
dm(subqueryDebug, ['\nAttr2: ', Attr2,
|
||
|
|
'\nAttrRelsAfter: ', AttrRelsAfter]),
|
||
|
|
findall(A, queryAttr(A), QueryAttrs),
|
||
|
|
assert(currentAttrs(QueryAttrs)),
|
||
|
|
findall([R, RR], queryRel(R, RR), QueryRels),
|
||
|
|
assert(currentRels(QueryRels)),
|
||
|
|
findall(V, variable(V, _), Variables),
|
||
|
|
assert(currentVariables(Variables)),
|
||
|
|
enterSubquery(predicate), % NVK ADDED
|
||
|
|
lookupSubquery(Query, Query2),
|
||
|
|
getSubqueryCurrent(SQID), % NVK ADDED
|
||
|
|
leaveSubquery, % NVK ADDED
|
||
|
|
dm(subqueryDebug, ['\nQuery2: ', Query2]),
|
||
|
|
correlationRels(Query2, Rels),
|
||
|
|
dm(subqueryDebug, ['\nRels: ', Rels]),
|
||
|
|
relsAfter(Rels, AttrRelsAfter, RelsAfter), !,
|
||
|
|
dm(subqueryDebug, ['\nRelsAfter: ', RelsAfter]),
|
||
|
|
Query3 = subquery(SQID, Query2, RelsAfter), % NVK MODIFIED
|
||
|
|
Pred2 =.. [not, Attr2, in(Query3)],
|
||
|
|
retractall(currentAttrs(_)),
|
||
|
|
retractall(currentRels(_)),
|
||
|
|
retractall(currentVariables(_)),
|
||
|
|
dm(subqueryDebug, ['\nPred2: ', Pred2]),
|
||
|
|
subquerySelectivity(Pred2, RelsAfter).
|
||
|
|
|
||
|
|
% default case, can fail for selection RelsAfter = [_G12345]
|
||
|
|
lookupSubqueryPred(Pred, Pred2, RelsBefore, RelsAfter) :-
|
||
|
|
isSubqueryPred1(Pred),
|
||
|
|
dm(subqueryDebug, ['\nlookupSubqueryPred 1\nPred: ', Pred]),
|
||
|
|
Pred =.. [Op, Attr, Query],
|
||
|
|
dm(subqueryDebug,
|
||
|
|
['\nOp: ', Op,
|
||
|
|
'\nAttr: ', Attr,
|
||
|
|
'\nQuery: ', Query,
|
||
|
|
'\nRelsAfter: ', RelsAfter]),
|
||
|
|
lookupPred1(Attr, Attr2, RelsBefore, AttrRelsAfter),
|
||
|
|
dm(subqueryDebug, ['\nAttr2: ', Attr2,
|
||
|
|
'\nAttrRelsAfter: ', AttrRelsAfter]),
|
||
|
|
findall(A, queryAttr(A), QueryAttrs),
|
||
|
|
assert(currentAttrs(QueryAttrs)),
|
||
|
|
findall([R, RR], queryRel(R, RR), QueryRels),
|
||
|
|
assert(currentRels(QueryRels)),
|
||
|
|
findall(V, variable(V, _), Variables),
|
||
|
|
assert(currentVariables(Variables)),
|
||
|
|
enterSubquery(predicate), % NVK ADDED
|
||
|
|
lookupSubquery(Query, Query2),
|
||
|
|
getSubqueryCurrent(SQID), % NVK ADDED
|
||
|
|
leaveSubquery, % NVK ADDED
|
||
|
|
dm(subqueryDebug, ['\nQuery2: ', Query2]),
|
||
|
|
correlationRels(Query2, Rels),
|
||
|
|
dm(subqueryDebug, ['\nRels: ', Rels]),
|
||
|
|
relsAfter(Rels, AttrRelsAfter, RelsAfter), !,
|
||
|
|
dm(subqueryDebug, ['\nRelsAfter: ', RelsAfter]),
|
||
|
|
Query3 = subquery(SQID, Query2, RelsAfter), % NVK MODIFIED
|
||
|
|
Pred2 =.. [Op, Attr2, Query3],
|
||
|
|
retractall(currentAttrs(_)),
|
||
|
|
retractall(currentRels(_)),
|
||
|
|
retractall(currentVariables(_)),
|
||
|
|
dm(subqueryDebug, ['\nPred2: ', Pred2]),
|
||
|
|
subquerySelectivity(Pred2, RelsAfter).
|
||
|
|
|
||
|
|
% remove side effects, if previous predicate failed
|
||
|
|
lookupSubqueryPred(_, _, _, _) :-
|
||
|
|
currentAttrs(QueryAttrs),
|
||
|
|
findall(A,
|
||
|
|
( queryAttr(A),
|
||
|
|
not(member(A, QueryAttrs)),
|
||
|
|
retract(queryAttr(A))
|
||
|
|
),
|
||
|
|
_),
|
||
|
|
retractall(currentAttrs(_)),
|
||
|
|
fail.
|
||
|
|
|
||
|
|
% case negated predicate
|
||
|
|
lookupSubqueryPred(not(Pred), not(Pred2), RelsBefore, RelsAfter) :-
|
||
|
|
isSubqueryPred1(not(Pred)),
|
||
|
|
dm(subqueryDebug, ['\nlookupSubqueryPred 2\nPred: ', not(Pred)]),
|
||
|
|
Pred =.. [Op, Query],
|
||
|
|
dm(subqueryDebug,
|
||
|
|
['\nOp: ', Op,
|
||
|
|
'\nQuery: ', Query]),
|
||
|
|
enterSubquery(predicate), % NVK ADDED
|
||
|
|
lookupSubquery(Query, Query2),
|
||
|
|
getSubqueryCurrent(SQID), % NVK ADDED
|
||
|
|
leaveSubquery, % NVK ADDED
|
||
|
|
dm(subqueryDebug, ['\nQuery2: ', Query2]),
|
||
|
|
correlationRels(Query2, Rels),
|
||
|
|
append(Rels, RelsBefore, RelsAfter),
|
||
|
|
Query3 = subquery(SQID, Query2, RelsAfter), % NVK MODIFIED
|
||
|
|
Pred2 =.. [Op, Query3],
|
||
|
|
dm(subqueryDebug, ['\nPred2: ', not(Pred2)]),
|
||
|
|
subquerySelectivity(not(Pred2), RelsAfter).
|
||
|
|
|
||
|
|
% default case for join predicates
|
||
|
|
lookupSubqueryPred(Pred, Pred2, RelsBefore, RelsAfter) :-
|
||
|
|
isSubqueryPred1(Pred),
|
||
|
|
dm(subqueryDebug, ['\nlookupSubqueryPred 2\nPred: ', Pred]),
|
||
|
|
Pred =.. [Op, Query],
|
||
|
|
dm(subqueryDebug,
|
||
|
|
['\nOp: ', Op,
|
||
|
|
'\nQuery: ', Query]),
|
||
|
|
enterSubquery(predicate), % NVK ADDED
|
||
|
|
lookupSubquery(Query, Query2),
|
||
|
|
getSubqueryCurrent(SQID), % NVK ADDED
|
||
|
|
leaveSubquery, % NVK ADDED
|
||
|
|
dm(subqueryDebug, ['\nQuery2: ', Query2]),
|
||
|
|
correlationRels(Query2, Rels),
|
||
|
|
append(Rels, RelsBefore, RelsAfter),
|
||
|
|
Query3 = subquery(SQID, Query2, RelsAfter),
|
||
|
|
Pred2 =.. [Op, Query3],
|
||
|
|
dm(subqueryDebug, ['\nPred2: ', Pred2]),
|
||
|
|
subquerySelectivity(Pred2, RelsAfter).
|
||
|
|
|
||
|
|
containsSubqueryPred(Pred) :-
|
||
|
|
not(is_list(Pred)),
|
||
|
|
isSubqueryPred1(Pred).
|
||
|
|
|
||
|
|
containsSubqueryPred([Pred | Rest]) :-
|
||
|
|
isSubqueryPred1(Pred) ;
|
||
|
|
containsSubqueryPred(Rest).
|
||
|
|
|
||
|
|
isSubqueryPred1(not(Pred)) :-
|
||
|
|
isSubqueryPred1(Pred).
|
||
|
|
|
||
|
|
isSubqueryPred1(Pred) :-
|
||
|
|
compound(Pred),
|
||
|
|
Pred =.. [Op, _, Subquery],
|
||
|
|
isSubqueryOp(Op),
|
||
|
|
Subquery =.. [from, _, _].
|
||
|
|
|
||
|
|
isSubqueryPred1(Pred) :-
|
||
|
|
compound(Pred),
|
||
|
|
Pred =.. [not, _, in(Subquery)],
|
||
|
|
Subquery =.. [from, _, _].
|
||
|
|
|
||
|
|
isSubqueryPred1(Pred) :-
|
||
|
|
compound(Pred),
|
||
|
|
Pred =.. [Op, Subquery],
|
||
|
|
isSubqueryOp(Op),
|
||
|
|
Subquery =.. [from, _, _].
|
||
|
|
|
||
|
|
isSubqueryPred1(Pred) :-
|
||
|
|
compound(Pred),
|
||
|
|
Pred =.. [Op, _, QuantifiedPred],
|
||
|
|
QuantifiedPred =.. [Quantifier, Subquery],
|
||
|
|
isComparisonOp(Op),
|
||
|
|
isQuantifier(Quantifier),
|
||
|
|
Subquery =.. [from, _, _].
|
||
|
|
|
||
|
|
isSubqueryPred1(Pred) :-
|
||
|
|
compound(Pred),
|
||
|
|
Pred =.. [Op, _, Subquery],
|
||
|
|
isSubqueryOp(Op),
|
||
|
|
isSubquery(Subquery).
|
||
|
|
|
||
|
|
isSubqueryPred1(Pred) :-
|
||
|
|
compound(Pred),
|
||
|
|
Pred =.. [not, _, in(Subquery)],
|
||
|
|
isSubquery(Subquery).
|
||
|
|
|
||
|
|
isSubqueryPred1(Pred) :-
|
||
|
|
compound(Pred),
|
||
|
|
Pred =.. [Op, Subquery],
|
||
|
|
isSubqueryOp(Op),
|
||
|
|
isSubquery(Subquery).
|
||
|
|
|
||
|
|
isSubqueryPred1(Pred) :-
|
||
|
|
compound(Pred),
|
||
|
|
Pred =.. [Op, _, QuantifiedPred],
|
||
|
|
QuantifiedPred =.. [Quantifier, Subquery],
|
||
|
|
isComparisonOp(Op),
|
||
|
|
isQuantifier(Quantifier),
|
||
|
|
isSubquery(Subquery).
|
||
|
|
|
||
|
|
isSubqeryPred1(exists(Subquery)) :-
|
||
|
|
isSubquery(Subquery).
|
||
|
|
|
||
|
|
isSubquery(subquery(_, _, _)). % NVK MODIFIED NR
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Find all relations referenced in predicates of ~Query~ which are not part
|
||
|
|
of the from-clause.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
correlationRels(Query, OuterRels) :-
|
||
|
|
\+ optimizerOption(nestedRelations), % NVK ADDED NR
|
||
|
|
removeCorrelatedPreds(Query, _, Preds),
|
||
|
|
usedRels(Preds, Rels),
|
||
|
|
Query =.. [from, _, Where],
|
||
|
|
Where =.. [where, InnerRels, _],
|
||
|
|
findall(Rel, ( member(Rel, Rels), not(member(Rel, InnerRels)) ), OuterRels),
|
||
|
|
dm(subqueryDebug, ['\ncorrelationRels_OuterRels: ', OuterRels]),
|
||
|
|
!. % NVK ADDED NR
|
||
|
|
|
||
|
|
correlationRels(select _ from InnerRels, InnerRels) :-
|
||
|
|
\+ optimizerOption(nestedRelations),
|
||
|
|
not(InnerRels =.. [where | _ ]),
|
||
|
|
!. % NVK ADDED NR
|
||
|
|
|
||
|
|
/*
|
||
|
|
NVK ADDED NR
|
||
|
|
Replaced to reflect that a subquery can now be a correlated predicates if the
|
||
|
|
from clause contains a attribute from the outer query. Otherwiese queries like test query no. 9 would not be possible with the current pog optimizer.
|
||
|
|
|
||
|
|
*/
|
||
|
|
correlationRels(Query, OuterRels3) :-
|
||
|
|
optimizerOption(nestedRelations),
|
||
|
|
Query =.. [from, _, Where],
|
||
|
|
( (
|
||
|
|
Where =.. [where, InnerRels, _],
|
||
|
|
removeCorrelatedPreds(Query, _, Preds)
|
||
|
|
) ->
|
||
|
|
(
|
||
|
|
usedRels(Preds, Rels),
|
||
|
|
findall(Rel, (member(Rel, Rels), not(member(Rel, InnerRels))), OuterRels)
|
||
|
|
)
|
||
|
|
;
|
||
|
|
% no sql predicates
|
||
|
|
(
|
||
|
|
OuterRels=[],
|
||
|
|
makeList(Where, InnerRels)
|
||
|
|
)
|
||
|
|
),
|
||
|
|
|
||
|
|
findall(ParentQueryRel, (
|
||
|
|
member(Rel2, InnerRels),
|
||
|
|
Rel2=rel(T, _),
|
||
|
|
%T=..[arel|_],
|
||
|
|
T=..[irrel,arel|_],
|
||
|
|
toParentQueryRel(Rel2, ParentQueryRel)
|
||
|
|
), OuterRels2),
|
||
|
|
append(OuterRels, OuterRels2, OuterRels3),
|
||
|
|
dm(subqueryDebug, ['\ncorrelationRels_OuterRels 1: ', OuterRels3]),
|
||
|
|
!.
|
||
|
|
% NVK ADDED NR END
|
||
|
|
|
||
|
|
correlationRels(all(Query), OuterRels) :-
|
||
|
|
correlationRels(Query, OuterRels).
|
||
|
|
|
||
|
|
correlationRels(any(Query), OuterRels) :-
|
||
|
|
correlationRels(Query, OuterRels).
|
||
|
|
|
||
|
|
/*
|
||
|
|
NVK ADDED NR
|
||
|
|
Note that this arel attribute can only come from the direct surrounded query
|
||
|
|
because otherwise the optimization strategy can't handle this case.
|
||
|
|
The error that will occur then is that the pog creation fails.
|
||
|
|
|
||
|
|
*/
|
||
|
|
toParentQueryRel(Rel, ParentQueryRel) :-
|
||
|
|
Rel=rel(T, _),
|
||
|
|
T=irrel(_, _, _, _, _, _, TypeSpec),
|
||
|
|
TypeSpec=arel(RelVar:_, _, _, _, _),
|
||
|
|
findBinding(RelVar, variable(RelVar, ParentQueryRel), _),
|
||
|
|
!.
|
||
|
|
|
||
|
|
|
||
|
|
toParentQueryRel(Rel, ParentQueryRel) :-
|
||
|
|
Rel=rel(T, _),
|
||
|
|
T=irrel(_, _, _, _, _, _, TypeSpec),
|
||
|
|
TypeSpec=arel((*):AttrDC, _, _, _, _),
|
||
|
|
|
||
|
|
findAttrLists(attribute, _, *, Rel2, AttrDesc),
|
||
|
|
nrSimpleFindAttribute(AttrDC, AttrDesc, _),
|
||
|
|
Rel2=ParentQueryRel, !.
|
||
|
|
|
||
|
|
toParentQueryRel(Rel, ParentQueryRel) :-
|
||
|
|
!,
|
||
|
|
throw(
|
||
|
|
error_Internal(subqueries_toParentQueryRel(Rel, ParentQueryRel)::failed)).
|
||
|
|
% NVK ADDED NR END
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Collect the relations used in the given predicate list.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
usedRels([], []).
|
||
|
|
usedRels([ pr(_, Rel) | Rest ], [ Rel | RelRest]) :-
|
||
|
|
usedRels(Rest, RelRest).
|
||
|
|
|
||
|
|
usedRels([ pr(_, Rel1, Rel2) | Rest ], [ Rel1 | [ Rel2 | RelRest ]]) :-
|
||
|
|
usedRels(Rest, RelRest).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
---- removeCorrelatedPreds(+Query1, -Query2, -Preds)
|
||
|
|
----
|
||
|
|
|
||
|
|
Strip ~Query1~ of all correlated predicates, i.e. all predicates referencing
|
||
|
|
relations not contained in the from-clause. ~Query2~ is the stripped query,
|
||
|
|
~Preds~ is the list of predicates removed from ~Query1~.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
removeCorrelatedPreds(Query groupby Attrs, Query2 groupby Attrs, Pred) :-
|
||
|
|
removeCorrelatedPreds(Query, Query2, Pred).
|
||
|
|
|
||
|
|
removeCorrelatedPreds(Query orderby Attrs, Query2 orderby Attrs, Pred) :-
|
||
|
|
removeCorrelatedPreds(Query, Query2, Pred).
|
||
|
|
|
||
|
|
removeCorrelatedPreds(Query first N, Query2 first N, Pred) :-
|
||
|
|
removeCorrelatedPreds(Query, Query2, Pred).
|
||
|
|
|
||
|
|
removeCorrelatedPreds(Query last N, Query2 last N, Pred) :-
|
||
|
|
removeCorrelatedPreds(Query, Query2, Pred).
|
||
|
|
|
||
|
|
|
||
|
|
removeCorrelatedPreds(select Attrs from Rels where [],
|
||
|
|
select Attrs from Rels, []) :-
|
||
|
|
ground(Attrs),
|
||
|
|
ground(Rels).
|
||
|
|
|
||
|
|
removeCorrelatedPreds(Select from Rels where [ Pred | Rest ], Query2,
|
||
|
|
CorrelatedPreds) :-
|
||
|
|
removeCorrelatedPred(Rels, Pred, Pred2, CorrelatedPred),
|
||
|
|
removeCorrelatedPreds(Select from Rels where Rest, Query, CorrelatedRest),
|
||
|
|
CorrelatedPreds1 = [ CorrelatedPred | CorrelatedRest ],
|
||
|
|
flatten(CorrelatedPreds1, CorrelatedPreds),
|
||
|
|
appendPred(Query, Pred2, Query2).
|
||
|
|
|
||
|
|
% NVK ADDED NR
|
||
|
|
removeCorrelatedPreds(select Attrs from Rels, select Attrs from Rels, []).
|
||
|
|
% NVK ADDED NR END
|
||
|
|
|
||
|
|
removeCorrelatedPred(Rels, pr(P, Rel), pr(P, Rel), []) :-
|
||
|
|
member(Rel, Rels).
|
||
|
|
|
||
|
|
removeCorrelatedPred(Rels, pr(P, Rel1, Rel2), pr(P, Rel1, Rel2), []) :-
|
||
|
|
member(Rel1, Rels),
|
||
|
|
member(Rel2, Rels).
|
||
|
|
|
||
|
|
removeCorrelatedPred(_, Pred, [], Pred).
|
||
|
|
|
||
|
|
/*
|
||
|
|
---- appendQuery(+Query, +PredList, -Query2)
|
||
|
|
----
|
||
|
|
|
||
|
|
Append predicates to the predicate list of ~Query~.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
appendPred(Query, [], Query).
|
||
|
|
appendPred(Select from Rels where Preds, Pred, Select from Rels where Preds2) :-
|
||
|
|
makeList(Pred, PredList),
|
||
|
|
makeList(Preds, PredsList),
|
||
|
|
append(PredList, PredsList, Preds2).
|
||
|
|
|
||
|
|
appendPred(Select from Rels, Pred, Select from Rels where [Pred]).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Add to predicates to an execution plan. This predicate is used to reappend
|
||
|
|
correlated predicates after the translation of the stripped query to an
|
||
|
|
execution plan.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
addCorrelatedPreds(Plan, Plan, []).
|
||
|
|
|
||
|
|
addCorrelatedPreds(Plan, PlanOut, [ Pred | Rest ]) :-
|
||
|
|
addCorrelatedPred(Plan, Plan2, Pred),
|
||
|
|
addCorrelatedPreds(Plan2, PlanOut, Rest).
|
||
|
|
|
||
|
|
addCorrelatedPred(simpleAggrNoGroupby(Op, Plan, Attr),
|
||
|
|
simpleAggrNoGroupby(Op, filter(Plan, P), Attr), pr(P, _, _)).
|
||
|
|
|
||
|
|
addCorrelatedPred(consume(project(Stream, Attrs)),
|
||
|
|
consume(project(filter(Stream, P), Attrs)), pr(P, _, _)).
|
||
|
|
% NVK ADDED NR
|
||
|
|
addCorrelatedPred(aconsume(project(Stream, Attrs)),
|
||
|
|
aconsume(project(filter(Stream, P), Attrs)), pr(P, _, _)).
|
||
|
|
|
||
|
|
addCorrelatedPred(aconsume(Plan),
|
||
|
|
aconsume(filter(Plan, P)), pr(P, _, _)).
|
||
|
|
% NVK ADDED NR END
|
||
|
|
|
||
|
|
|
||
|
|
addCorrelatedPred(consume(Plan),
|
||
|
|
consume(filter(Plan, P)), pr(P, _, _)).
|
||
|
|
addCorrelatedPred(count(project(Stream, Attrs)),
|
||
|
|
count(project(filter(Stream, P), Attrs)), pr(P, _, _)).
|
||
|
|
|
||
|
|
addCorrelatedPred(count(Plan),
|
||
|
|
count(filter(Plan, P)), pr(P, _, _)).
|
||
|
|
|
||
|
|
addCorrelatedPred(Plan,
|
||
|
|
filter(Plan, P), pr(P, _, _)).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Finds the correct renaming for a relation in an execution plan.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
isNameOf(Param, Rel) :-
|
||
|
|
stack(streamRel, SR),
|
||
|
|
stack(streamName, SN),
|
||
|
|
length(SR, N),
|
||
|
|
length(SN, N),
|
||
|
|
peak(streamName, Param),
|
||
|
|
peak(streamRel, Rel).
|
||
|
|
|
||
|
|
isNameOf(txx1, Rel) :-
|
||
|
|
peak(streamName, txx1),
|
||
|
|
peak(streamRel, 2, Rel).
|
||
|
|
|
||
|
|
isNameOf(Param, Rel) :-
|
||
|
|
Param \= txx1,
|
||
|
|
peak(streamName, Param),
|
||
|
|
peak(streamRel, Rel).
|
||
|
|
|
||
|
|
isNameOf(Param, Rel) :-
|
||
|
|
stack(streamRel, SR),
|
||
|
|
stack(streamName, SN),
|
||
|
|
length(SR, N),
|
||
|
|
length(SN, N1),
|
||
|
|
N1 < N,
|
||
|
|
peak(streamName, Param),
|
||
|
|
peak(streamRel, 2, Rel).
|
||
|
|
|
||
|
|
isNameOf(Param, Rel) :-
|
||
|
|
peak(streamName, 2, Param),
|
||
|
|
peak(streamRel, 2, Rel).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Apply renaming to the correlated predicates, so that it matches the renaming of the
|
||
|
|
base relation.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
transformCorrelatedPreds(_, _, [], []).
|
||
|
|
|
||
|
|
transformCorrelatedPreds(Rels, Param, [pr(P, Rel1, Rel2)], [Pred3]) :-
|
||
|
|
not(member(Rel1, Rels)),
|
||
|
|
not(member(Rel2, Rels)),
|
||
|
|
isNameOf(Param, Rel1),
|
||
|
|
isNameOf(Param, Rel2),
|
||
|
|
transformPred(pr(P, Rel1, Rel2), Param, 1, Pred2),
|
||
|
|
transformPred(Pred2, Param, 2, Pred3).
|
||
|
|
|
||
|
|
transformCorrelatedPreds(Rels, Param, [pr(P, Rel1, Rel2)], [Pred2]) :-
|
||
|
|
not(member(Rel1, Rels)),
|
||
|
|
isNameOf(Param, Rel1),
|
||
|
|
transformPred(pr(P, Rel1, Rel2), Param, 1, Pred2).
|
||
|
|
|
||
|
|
transformCorrelatedPreds(Rels, Param, [pr(P, Rel1, Rel2)], [Pred2]) :-
|
||
|
|
not(member(Rel2, Rels)),
|
||
|
|
isNameOf(Param, Rel2),
|
||
|
|
transformPred(pr(P, Rel1, Rel2), Param, 2, Pred2).
|
||
|
|
|
||
|
|
transformCorrelatedPreds(_, _, [pr(P, Rel1, Rel2)], [pr(P, Rel1, Rel2)]).
|
||
|
|
|
||
|
|
|
||
|
|
transformCorrelatedPreds(Rels, Param, [pr(P, Rel1, Rel2)], [_]) :-
|
||
|
|
write('Rels: '), write(Rels), nl,
|
||
|
|
write('Param: '), write(Param), nl,
|
||
|
|
write('P: '), write(P), nl,
|
||
|
|
write('Rel1: '), write(Rel1), nl,
|
||
|
|
write('Rel2: '), write(Rel2), nl, !,
|
||
|
|
( firstStream(A) ; true ),
|
||
|
|
write('firstStream: '), write(A), nl,
|
||
|
|
throw(error_Internal(subqueries_transformCorrelatedPreds::notImplemented::_)).
|
||
|
|
|
||
|
|
transformCorrelatedPreds(Rels, Param, [Pred | Rest], [Pred2 | Rest2]) :-
|
||
|
|
transformCorrelatedPreds(Rels, Param, [Pred], [Pred2]),
|
||
|
|
transformCorrelatedPreds(Rels, Param, Rest, Rest2).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Apply the correct renaming to an attribute expression, so that it matches
|
||
|
|
the renaming of the base relations.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
% If there is a name ~Param~ for relation Rel, Rel is not contained in
|
||
|
|
% list Rels and Attr is attribute of Rel, then rename Attr with ~Param~
|
||
|
|
% case aliased attribute, Rel is first stream
|
||
|
|
transformAttrExpr(attr(Var:Attr, Arg, Case), Param, _,
|
||
|
|
attribute(Param, attrname(attr(Var:Attr, Arg, Case))), Rels) :-
|
||
|
|
peak(streamRel, rel(Rel, Var)),
|
||
|
|
isNameOf(Param, rel(Rel, Var)),
|
||
|
|
not(member(rel(Rel, Var), Rels)),
|
||
|
|
findAttribute(Attr, rel(Rel, Var)).
|
||
|
|
|
||
|
|
% If there is a name ~Param~ for relation Rel, Rel is not contained in
|
||
|
|
% list Rels and Attr is attribute of Rel, then rename Attr with ~Param~
|
||
|
|
% case aliased attribute, Rel is second stream
|
||
|
|
transformAttrExpr(attr(Var:Attr, Arg, Case), Param, _,
|
||
|
|
attribute(Param, attrname(attr(Var:Attr, Arg, Case))), Rels) :-
|
||
|
|
peak(streamRel, 2, rel(Rel, Var)),
|
||
|
|
isNameOf(Param, rel(Rel, Var)),
|
||
|
|
not(member(rel(Rel, Var), Rels)),
|
||
|
|
findAttribute(Attr, rel(Rel, Var)).
|
||
|
|
|
||
|
|
% If there is a name ~Param~ for relation Rel, Rel is not contained in
|
||
|
|
% list Rels and Attr is attribute of Rel, then rename Attr with ~Param~
|
||
|
|
% case Rel is first stream
|
||
|
|
transformAttrExpr(attr(Attr, Arg, Case), Param, _,
|
||
|
|
attribute(Param, attrname(attr(Attr, Arg, Case))), Rels) :-
|
||
|
|
peak(streamRel, rel(Rel, Var)),
|
||
|
|
isNameOf(Param, rel(Rel, Var)),
|
||
|
|
not(member(rel(Rel, Var), Rels)),
|
||
|
|
findAttribute(Attr, rel(Rel, Var)).
|
||
|
|
|
||
|
|
% If there is a name ~Param~ for relation Rel, Rel is not contained in
|
||
|
|
% list Rels and Attr is attribute of Rel, then rename Attr with ~Param~
|
||
|
|
% case Rel is second stream
|
||
|
|
transformAttrExpr(attr(Attr, Arg, Case), Param, _,
|
||
|
|
attribute(Param, attrname(attr(Attr, Arg, Case))), Rels) :-
|
||
|
|
peak(streamRel, 2, rel(Rel, Var)),
|
||
|
|
isNameOf(Param, rel(Rel, Var)),
|
||
|
|
not(member(rel(Rel, Var), Rels)),
|
||
|
|
findAttribute(Attr, rel(Rel, Var)).
|
||
|
|
|
||
|
|
transformAttrExpr(attribute(Param, attrname(attr(Attr, Arg, Case))),
|
||
|
|
_, _, attribute(Param, attrname(attr(Attr, Arg, Case))), _) :- !.
|
||
|
|
|
||
|
|
transformAttrExpr([], _, _, [], _).
|
||
|
|
transformAttrExpr([Arg1|Args1], Param, Arg, [Arg1T|Args1T], Rels) :-
|
||
|
|
transformAttrExpr(Arg1, Param, Arg, Arg1T, Rels),
|
||
|
|
transformAttrExpr(Args1, Param, Arg, Args1T, Rels).
|
||
|
|
|
||
|
|
transformAttrExpr(Pred, Param, Arg, Pred2, Rels) :-
|
||
|
|
compound(Pred),
|
||
|
|
not(is_list(Pred)),
|
||
|
|
Pred =.. [T|Args],
|
||
|
|
transformAttrExpr(Args, Param, Arg, Args2, Rels),
|
||
|
|
Pred2 =.. [T|Args2].
|
||
|
|
|
||
|
|
transformAttrExpr(Pred, _, _, Pred, _).
|
||
|
|
|
||
|
|
findAttribute(Attr, rel(Rel, *)) :-
|
||
|
|
isAttributeOf(Attr, Rel).
|
||
|
|
|
||
|
|
findAttribute(Attr, rel(Rel, Var)) :-
|
||
|
|
isAttributeOf(Attr, Rel as Var).
|
||
|
|
|
||
|
|
% renaming for selectivity queries, handling of operator ~not in~.
|
||
|
|
subqueryTransformPred(Pred, T, Arg, Pred3) :-
|
||
|
|
Pred =.. [not, Attr, InExpr],
|
||
|
|
InExpr =.. [in, Query],
|
||
|
|
Pred1 =.. [in, Attr, Query],
|
||
|
|
subqueryTransformPred(Pred1, T, Arg, Pred2),
|
||
|
|
Pred2 =.. [in, Attr2, Query2],
|
||
|
|
InExpr2 =.. [in, Query2],
|
||
|
|
Pred3 =.. [not, Attr2, InExpr2].
|
||
|
|
|
||
|
|
% renaming for selectivity queries
|
||
|
|
subqueryTransformPred(Pred, T, Arg, Pred2) :-
|
||
|
|
Pred =.. [Op, Attr, Query],
|
||
|
|
isSubqueryOp(Op),
|
||
|
|
extractQuery(Query, Query1),
|
||
|
|
Query =.. [subquery, SQID, _, OuterRels], % NVK MODIFIED NR
|
||
|
|
Query1 =.. [from, Select, Where],
|
||
|
|
Where =.. [where, Rels, Preds],
|
||
|
|
transformAttrExpr(Select, T, Arg, Select2, Rels),
|
||
|
|
transformAttrExpr(Attr, T, Arg, Attr2, []),
|
||
|
|
removeCorrelatedPreds(Query1, _, CorrelatedPreds),
|
||
|
|
transformCorrelatedPreds(Rels, txx1, CorrelatedPreds, Preds2),
|
||
|
|
dm(subqueryDebug,
|
||
|
|
['\nsubqueryTransformPred\n\tCorrelatedPreds: ', CorrelatedPreds,
|
||
|
|
'\n\tPreds2: ', Preds2]),
|
||
|
|
dm(subqueryDebug, ['\nPreds: ', Preds]),
|
||
|
|
append(CorrelatedPreds, SimplePreds, Preds),
|
||
|
|
dm(subqueryDebug, ['\nSimplePreds: ', SimplePreds]),
|
||
|
|
append(Preds2, SimplePreds, PredList),
|
||
|
|
dm(subqueryDebug, ['\nPredList: ', PredList]),
|
||
|
|
Where2 =.. [where, Rels, PredList],
|
||
|
|
Query2 =.. [from, Select2, Where2],
|
||
|
|
Pred2 =.. [Op, Attr2, subquery(SQID, Query2, OuterRels)], % NVK MODIFIED NR
|
||
|
|
clearQuery(Query).
|
||
|
|
|
||
|
|
subqueryTransformPred(attribute(Param, attrname(attr(Attr, Arg, Case))),
|
||
|
|
_, Arg, attribute(Param, attrname(attr(Attr, Arg, Case)))) :- !.
|
||
|
|
|
||
|
|
transformPreds([], _, _, []).
|
||
|
|
transformPreds([Pred], Param, Arg, [Pred2]) :-
|
||
|
|
transformPred(Pred, Param, Arg, Pred2).
|
||
|
|
transformPreds([ Pred | Rest ], Param, Arg, [ Pred2 | Rest2 ] ) :-
|
||
|
|
not(is_list(Pred)),
|
||
|
|
not(Pred = [[]]),
|
||
|
|
transformPred(Pred, Param, Arg, Pred2),
|
||
|
|
transformPreds(Rest, Param, Arg, Rest2).
|
||
|
|
|
||
|
|
simpleSubqueryPred(pr(P, A, B), Simple) :-
|
||
|
|
simple1(P, A, B, Simple).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Replacement of predicate ~simple(+P, +Rel1, +Rel2, -SimplePredicate)~ of file
|
||
|
|
~statistics.pl~ which handles subquery predicates correctly.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
simple1(attr(Var:Attr, 0, _), _, _, Rel:Attr) :-
|
||
|
|
usedAttr(rel(Rel, Var), attr(Var:Attr, 0, _)),
|
||
|
|
!.
|
||
|
|
|
||
|
|
simple1(attr(Attr, 0, _), _, _, Rel:Attr) :-
|
||
|
|
usedAttr(rel(Rel, *), attr(Attr, 0, _)),
|
||
|
|
!.
|
||
|
|
|
||
|
|
simple1(attr(Var:Attr, 1, _), _, _, Rel:Attr) :-
|
||
|
|
usedAttr(rel(Rel, Var), attr(Var:Attr, 1, _)),
|
||
|
|
!.
|
||
|
|
|
||
|
|
simple1(attr(Attr, 1, _), _, _, Rel:Attr) :-
|
||
|
|
usedAttr(rel(Rel, *), attr(Attr, 1, _)),
|
||
|
|
!.
|
||
|
|
|
||
|
|
simple1(attr(Var:Attr, 2, _), _, _, Rel:Attr) :-
|
||
|
|
usedAttr(rel(Rel, Var), attr(Var:Attr, 2, _)),
|
||
|
|
!.
|
||
|
|
|
||
|
|
simple1(attr(Attr, 2, _), _, _, Rel:Attr) :-
|
||
|
|
usedAttr(rel(Rel, *), attr(Attr, 2, _)),
|
||
|
|
!.
|
||
|
|
|
||
|
|
simple1(dbobject(X),_,_,dbobject(X)) :- !.
|
||
|
|
|
||
|
|
simple1([], _, _, []) :- !.
|
||
|
|
simple1([A|Rest], Rel1, Rel2, [Asimple|RestSimple]) :-
|
||
|
|
simple1(A,Rel1,Rel2,Asimple),
|
||
|
|
simple1(Rest,Rel1,Rel2,RestSimple),
|
||
|
|
!.
|
||
|
|
simple1(Term, Rel1, Rel2, Simple) :-
|
||
|
|
compound(Term),
|
||
|
|
Term =.. [Op|Args],
|
||
|
|
simple1(Args, Rel1, Rel2, ArgsSimple),
|
||
|
|
Simple =..[Op|ArgsSimple],
|
||
|
|
!.
|
||
|
|
|
||
|
|
simple1(Term, _, _, Term).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
---- sampleSQ(+Rel, -SampleRel)
|
||
|
|
----
|
||
|
|
|
||
|
|
Returns the corresponding sample relation for selectivity queries for a
|
||
|
|
subquery predicate. At the moment the selection sample is used.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
sampleSQ([], []).
|
||
|
|
|
||
|
|
sampleSQ(rel(Rel, Var), rel(Rel2, Var)) :-
|
||
|
|
not(sampleS(_, rel(Rel, Var))),
|
||
|
|
not(sampleJ(_, rel(Rel, Var))),
|
||
|
|
ensureSampleSexists(Rel),
|
||
|
|
sampleS(rel(Rel, Var), rel(Rel2, Var)).
|
||
|
|
|
||
|
|
sampleSQ([ Rel | Rest ], [ Rel2 | Rest2 ]) :-
|
||
|
|
sampleSQ(Rel, Rel2),
|
||
|
|
sampleSQ(Rest, Rest2).
|
||
|
|
|
||
|
|
sampleSQ(Rel, Rel).
|
||
|
|
|
||
|
|
:- assert(maxSelCard(250000)).
|
||
|
|
:- assert(maxSampleCard(500)).
|
||
|
|
|
||
|
|
:- dynamic(currentLevel/1).
|
||
|
|
|
||
|
|
:- assert(currentLevel(0)).
|
||
|
|
|
||
|
|
ascendLevel :-
|
||
|
|
currentLevel(L),
|
||
|
|
L1 is L - 1,
|
||
|
|
retract(currentLevel(_)),
|
||
|
|
assert(currentLevel(L1)).
|
||
|
|
|
||
|
|
descendLevel :-
|
||
|
|
currentLevel(L),
|
||
|
|
L1 is L + 1,
|
||
|
|
retract(currentLevel(_)),
|
||
|
|
assert(currentLevel(L1)).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Stack handling for outer relations and their names. This information
|
||
|
|
is needed in the translation phase to apply the correct renaming to
|
||
|
|
attributes.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
streamName(Var) :-
|
||
|
|
push(streamName, Var).
|
||
|
|
|
||
|
|
clearStreamName :-
|
||
|
|
pop(streamName, _).
|
||
|
|
|
||
|
|
clearStreamName :-
|
||
|
|
my_concat_atom(['Pop empty', ' stack streamName'], ErrMsg),
|
||
|
|
throw(error_SQL(subqueries_streamName::malformedExpression::ErrMsg)).
|
||
|
|
|
||
|
|
clearStreamName(Var) :-
|
||
|
|
streamName(Var, _),
|
||
|
|
retract(streamName(Var, _)).
|
||
|
|
|
||
|
|
clearStreamName(_).
|
||
|
|
|
||
|
|
clearStreamNames :-
|
||
|
|
retractall(streamName(_, _)).
|
||
|
|
|
||
|
|
streamRel(Rel) :-
|
||
|
|
push(streamRel, Rel).
|
||
|
|
|
||
|
|
clearStreamRel :-
|
||
|
|
pop(streamRel, _).
|
||
|
|
|
||
|
|
clearStreamRel.
|
||
|
|
|
||
|
|
clearStreamRel(Rel) :-
|
||
|
|
peak(streamRel, Rel),
|
||
|
|
!,
|
||
|
|
pop(streamRel, Rel).
|
||
|
|
|
||
|
|
clearStreamRel(_).
|
||
|
|
|
||
|
|
clearStreamRel(Rel1, Rel2) :-
|
||
|
|
peak(streamRel, Rel2),
|
||
|
|
peak(streamRel, 2, Rel1),
|
||
|
|
!,
|
||
|
|
pop(streamRel, Rel2),
|
||
|
|
pop(streamRel, Rel1).
|
||
|
|
|
||
|
|
clearStreamRel(_, _).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Apply renaming to a subquery in a selectivity query.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
/*
|
||
|
|
Transforming Selection Predicates
|
||
|
|
|
||
|
|
---- transformQuery(+Rel, +Pred, +QueryIn, -QueryOut)
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
% no transformation, if subquery handling is deactivated
|
||
|
|
transformQuery(_, _, Query, Query) :-
|
||
|
|
not(optimizerOption(subqueries)).
|
||
|
|
|
||
|
|
% flag query as selectivity query
|
||
|
|
transformQuery(_, Pred, Query, Query2) :-
|
||
|
|
optimizerOption(subqueries),
|
||
|
|
assert(selectivityQuery(Pred)),
|
||
|
|
isSubqueryPred1(Pred),
|
||
|
|
% streamRel(Rel),
|
||
|
|
transformPlan(Query, Query2).
|
||
|
|
|
||
|
|
% no transformation for simple predicates
|
||
|
|
transformQuery(_, _, Query, Query).
|
||
|
|
|
||
|
|
% report error
|
||
|
|
transformQuery(_, _, Q, _) :-
|
||
|
|
not(optimizerOption(subqueries)),
|
||
|
|
throw(error_Internal(subqueries_transformQuery(Q)::notImplemented::_)).
|
||
|
|
|
||
|
|
/*
|
||
|
|
Transforming Join Predicates
|
||
|
|
|
||
|
|
---- transformQuery(+Rel1, +Rel2, +Pred, +QueryIn, JoinSize, -QueryOut)
|
||
|
|
----
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
% case loopsel for nested selection predicates
|
||
|
|
transformQuery(_, _, _, count(loopsel(Query, Fun)), JoinSize,
|
||
|
|
count(loopsel(head(Query, JoinSize), Fun))) :-
|
||
|
|
not(optimizerOption(subqueries)).
|
||
|
|
|
||
|
|
transformQuery(_, _, _, count(timeout(loopsel(Query, Fun), T)), JoinSize,
|
||
|
|
count(timeout(loopsel(head(Query, JoinSize), Fun), T))) :-
|
||
|
|
not(optimizerOption(subqueries)).
|
||
|
|
|
||
|
|
% case loopjoin for nested join predicates
|
||
|
|
transformQuery(_, _, _, count(filter(counter(loopjoin(Q, Fun), C), P)),
|
||
|
|
JoinSize,
|
||
|
|
count(filter(counter(loopjoin(head(Q, JoinSize), Fun), C), P))) :-
|
||
|
|
not(optimizerOption(subqueries)).
|
||
|
|
|
||
|
|
transformQuery(_,_,_,count(timeout(filter(counter(loopjoin(Q, Fun), C), P), T)),
|
||
|
|
JoinSize,
|
||
|
|
count(timeout(filter(counter(loopjoin(head(Q,JoinSize),Fun), C), P), T))) :-
|
||
|
|
not(optimizerOption(subqueries)).
|
||
|
|
|
||
|
|
% case symmjoin for nested non-bbox selection predicates
|
||
|
|
transformQuery(_, _, _,
|
||
|
|
count(symmjoin(Query1,Query2,Pred)), JoinSize,
|
||
|
|
count(symmjoin(head(Query1,JoinSize),Query2,Pred))) :-
|
||
|
|
not(optimizerOption(subqueries)).
|
||
|
|
|
||
|
|
transformQuery(_, _, _,
|
||
|
|
count(timeout(symmjoin(Query1,Query2,Pred),T)), JoinSize,
|
||
|
|
count(timeout(symmjoin(head(Query1,JoinSize),Query2,Pred),T))) :-
|
||
|
|
not(optimizerOption(subqueries)).
|
||
|
|
|
||
|
|
% case symmjoin for nested bbox selection predicates
|
||
|
|
transformQuery(_, _, _,
|
||
|
|
count(filter(counter(
|
||
|
|
symmjoin(Query1,Query2,P1),C1),P2)), JoinSize,
|
||
|
|
count(filter(counter(
|
||
|
|
symmjoin(head(Query1,JoinSize),Query2,P1),C1),P2))) :-
|
||
|
|
not(optimizerOption(subqueries)).
|
||
|
|
|
||
|
|
transformQuery(_, _, _,
|
||
|
|
count(timeout(filter(counter(
|
||
|
|
symmjoin(Query1,Query2,P1),C1),P2),T)), JoinSize,
|
||
|
|
count(timeout(filter(counter(
|
||
|
|
symmjoin(head(Query1,JoinSize),Query2,P1),C1),P2),T))) :-
|
||
|
|
not(optimizerOption(subqueries)).
|
||
|
|
|
||
|
|
% error: No more cases for not(optimizerOption(subqueries))
|
||
|
|
transformQuery(_, _, _, Q, JS, _) :-
|
||
|
|
not(optimizerOption(subqueries)),
|
||
|
|
throw(error_Internal(subqueries_transformQuery(Q, JS)::notImplemented::_)).
|
||
|
|
|
||
|
|
% case loopsel for nested selection predicates
|
||
|
|
transformQuery(_, _, Pred, count(loopsel(Query, Fun)), JoinSize,
|
||
|
|
count(loopsel(head(Query, JoinSize), Fun))) :-
|
||
|
|
not(isSubqueryPred1(Pred)).
|
||
|
|
|
||
|
|
transformQuery(_, _, Pred, count(timeout(loopsel(Query, Fun),T)), JoinSize,
|
||
|
|
count(timeout(loopsel(head(Query, JoinSize), Fun),T))) :-
|
||
|
|
not(isSubqueryPred1(Pred)).
|
||
|
|
|
||
|
|
% case symmjoin for nested non-bbox selection predicates
|
||
|
|
transformQuery(_, _, Pred, count(symmjoin(Q1,Q2,P)), JoinSize,
|
||
|
|
count(symmjoin(head(Q1,JoinSize),Q2,P))) :-
|
||
|
|
not(isSubqueryPred1(Pred)).
|
||
|
|
|
||
|
|
transformQuery(_, _, Pred, count(timeout(symmjoin(Q1,Q2,P),TO)), JoinSize,
|
||
|
|
count(timeout(symmjoin(head(Q1,JoinSize),Q2,P),TO))) :-
|
||
|
|
not(isSubqueryPred1(Pred)).
|
||
|
|
|
||
|
|
% case symmjoin for nested bbox selection predicates
|
||
|
|
transformQuery(_, _, Pred,
|
||
|
|
count(filter(counter(symmjoin(Q1,Q2,P2),C1),P1)), JoinSize,
|
||
|
|
count(filter(counter(
|
||
|
|
symmjoin(head(Q1,JoinSize),Q2,P2),C1),P1))) :-
|
||
|
|
not(isSubqueryPred1(Pred)).
|
||
|
|
|
||
|
|
transformQuery(_, _, Pred,
|
||
|
|
count(timeout(filter(counter(symmjoin(Q1,Q2,P2),C1),P1),TO)), JoinSize,
|
||
|
|
count(timeout(filter(counter(
|
||
|
|
symmjoin(head(Q1,JoinSize),Q2,P2),C1),P1),TO))) :-
|
||
|
|
not(isSubqueryPred1(Pred)).
|
||
|
|
|
||
|
|
% case loopjoin for nested join predicates
|
||
|
|
transformQuery(_, _, Pred, count(filter(counter(loopjoin(Q, Fun), C), P)),
|
||
|
|
JoinSize,
|
||
|
|
count(filter(counter(loopjoin(head(Q, JoinSize), Fun), C), P))) :-
|
||
|
|
not(isSubqueryPred1(Pred)).
|
||
|
|
|
||
|
|
transformQuery(_,_,Pred,count(timeout(filter(counter(loopjoin(Q, Fun),C),P),T)),
|
||
|
|
JoinSize,
|
||
|
|
count(timeout(filter(counter(loopjoin(head(Q, JoinSize), Fun), C), P),T))):-
|
||
|
|
not(isSubqueryPred1(Pred)).
|
||
|
|
|
||
|
|
% report error
|
||
|
|
transformQuery(_, _, _, Q, JS, _) :-
|
||
|
|
not(optimizerOption(subqueries)),
|
||
|
|
throw(error_Internal(subqueries_transformQuery(Q, JS)::notImplemented::_)).
|
||
|
|
|
||
|
|
% return JoinSize, which is calculated depending on the
|
||
|
|
% count of relations used in this query
|
||
|
|
transformQuery(_, _, Pred, Query, JoinSize, Query2) :-
|
||
|
|
optimizerOption(subqueries),
|
||
|
|
maxSampleCard(C),
|
||
|
|
retractall(maxSampleCard(_)),
|
||
|
|
NewSampleCard is min(JoinSize, C),
|
||
|
|
assert(maxSampleCard(NewSampleCard)),
|
||
|
|
transformPlan(Query, Query2),
|
||
|
|
sampleSize(S),
|
||
|
|
retractall(realJoinSize(Pred, _)),
|
||
|
|
assert(realJoinSize(Pred, S)).
|
||
|
|
|
||
|
|
:- dynamic(realJoinSize/2).
|
||
|
|
|
||
|
|
clearSelectivityQuery(_, Pred) :-
|
||
|
|
!,
|
||
|
|
retractall(selectivityQuery(Pred)).
|
||
|
|
|
||
|
|
clearSelectivityQuery(_, _, Pred) :-
|
||
|
|
!,
|
||
|
|
retractall(selectivityQuery(Pred)).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Predicates to count the number of relations which are part of a selectivity query.
|
||
|
|
The resulting number is used to calculate the size used in sampling.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
selectivityRel :-
|
||
|
|
selectivityRels(N),
|
||
|
|
retractall(selectivityRels(_)),
|
||
|
|
N1 is N + 1,
|
||
|
|
assert(selectivityRels(N1)).
|
||
|
|
|
||
|
|
selectivityRel :-
|
||
|
|
retractall(selectivityRels(_)),
|
||
|
|
assert(selectivityRels(1)).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Apply the sample sizes calculated to the selectivity query. Maximum cardinality
|
||
|
|
for a selectivity query is ~maxSelCard(selCard)~, maximum cardinality for a sample
|
||
|
|
relation is ~maxSampleCard(sampleCard)~. The cardinality used for sampling is
|
||
|
|
calculated as $\sqrt[N]{selCard}$, where N is the number of relations used in the
|
||
|
|
selectivity query.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
transformPlan(Plan, Plan) :-
|
||
|
|
not(selectivityQuery(_)).
|
||
|
|
|
||
|
|
transformPlan(Plan, Plan2) :-
|
||
|
|
sampleSize(C),
|
||
|
|
maxSampleCard(C1),
|
||
|
|
C < C1,
|
||
|
|
transformPlan1(Plan, Plan2, C),
|
||
|
|
retractall(sampleSize(_)).
|
||
|
|
|
||
|
|
% calculate sampleSize
|
||
|
|
transformPlan(Plan, Plan2) :-
|
||
|
|
retractall(selectivityRels(_)),
|
||
|
|
transformPlan1(Plan, Plan2, C),
|
||
|
|
selectivityRels(N),
|
||
|
|
maxSelCard(Max),
|
||
|
|
maxSampleCard(SampleSize),
|
||
|
|
A is 1 / N,
|
||
|
|
B is Max ** A,
|
||
|
|
C is min(SampleSize, floor(B)),
|
||
|
|
retractall(sampleSize(_)),
|
||
|
|
assert(sampleSize(C)).
|
||
|
|
|
||
|
|
transformPlan1([], [], _).
|
||
|
|
|
||
|
|
transformPlan1(pr(P, R1, R2), pr(P, R1, R2), _).
|
||
|
|
transformPlan1(pr(P, R1), pr(P, R1), _).
|
||
|
|
|
||
|
|
% Relation found, case feed, apply ~head~ operator
|
||
|
|
transformPlan1(feed(Rel), head(feed(Rel2), C), C) :-
|
||
|
|
sampleSQ(Rel, Rel2),
|
||
|
|
selectivityRel.
|
||
|
|
|
||
|
|
% Relation found, case feedproject, apply ~head~ operator
|
||
|
|
transformPlan1(feedproject(Rel, Attrs),
|
||
|
|
head(feedproject(Rel2, Attrs), C), C) :-
|
||
|
|
sampleSQ(Rel, Rel2),
|
||
|
|
selectivityRel.
|
||
|
|
|
||
|
|
% Relation found, only count relation
|
||
|
|
transformPlan1(rel(Rel, Var), rel(Rel, Var), _) :-
|
||
|
|
selectivityRel.
|
||
|
|
|
||
|
|
% NVK ADDED NR
|
||
|
|
% This is the case for arel access where there is no rel-term anymore available.
|
||
|
|
transformPlan1(afeed(Rel), head(afeed(Rel), C), C) :-
|
||
|
|
selectivityRel.
|
||
|
|
% NVK ADDED NR END
|
||
|
|
|
||
|
|
transformPlan1([ Plan | Rest ], [Plan2 | Rest2], C) :-
|
||
|
|
transformPlan1(Plan, Plan2, C),
|
||
|
|
transformPlan1(Rest, Rest2, C).
|
||
|
|
|
||
|
|
transformPlan1(Plan, Plan2, C) :-
|
||
|
|
compound(Plan),
|
||
|
|
not(is_list(Plan)),
|
||
|
|
Plan =.. [Op | Args],
|
||
|
|
transformPlan1(Args, Args2, C),
|
||
|
|
Plan2 =.. [Op | Args2].
|
||
|
|
|
||
|
|
transformPlan1(Plan, Plan, _).
|
||
|
|
|
||
|
|
getSubqueryTypeTree(subquery(_, Query, _), % NVK MODIFIED
|
||
|
|
OuterRels1, [subquery, TypeTree, DCType]) :-
|
||
|
|
newVariable(T),
|
||
|
|
subquery_to_plan(Query, simpleAggrNoGroupby(Op, Plan, Attr), T),
|
||
|
|
Plan2 =.. [Op, Plan, Attr],
|
||
|
|
getTypeTree(Plan2, OuterRels1, TypeTree),
|
||
|
|
TypeTree = [_, _, DCType],
|
||
|
|
!.
|
||
|
|
|
||
|
|
subqueryPredRel(_).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Assert information about the position of outer relations.
|
||
|
|
|
||
|
|
*/
|
||
|
|
joinRel([], _).
|
||
|
|
|
||
|
|
joinRel(feed(Rel), 1) :-
|
||
|
|
% retract(streamRel(_)),
|
||
|
|
assert(streamRel(Rel, 1)).
|
||
|
|
|
||
|
|
joinRel(feed(Rel), 2) :-
|
||
|
|
assert(streamRel(Rel, 2)).
|
||
|
|
|
||
|
|
joinRel(feedproject(Rel, _), 1) :-
|
||
|
|
% retractall(streamRel(_)),
|
||
|
|
assert(streamRel(Rel, 1)).
|
||
|
|
|
||
|
|
joinRel(feedproject(Rel, _), 2) :-
|
||
|
|
assert(streamRel(Rel, 2)).
|
||
|
|
|
||
|
|
joinRel([ Stream | Rest ], Arg) :-
|
||
|
|
joinRel(Stream, Arg),
|
||
|
|
joinRel(Rest, Arg).
|
||
|
|
|
||
|
|
joinRel(Stream, Arg) :-
|
||
|
|
compound(Stream),
|
||
|
|
not(is_list(Stream)),
|
||
|
|
Stream =.. [_ | Args],
|
||
|
|
joinRel(Args, Arg).
|
||
|
|
|
||
|
|
joinRel(_ ,_).
|
||
|
|
|
||
|
|
joinRels(_, _).
|
||
|
|
|
||
|
|
joinRels(Arg1, Arg2) :-
|
||
|
|
joinRel(Arg1, 1),
|
||
|
|
joinRel(Arg2, 2).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Extract a stream plan and its schema from an execution plan.
|
||
|
|
|
||
|
|
*/
|
||
|
|
extractStream(consume(project(StreamPlan, QueryAttr)),
|
||
|
|
StreamPlan, QueryAttr).
|
||
|
|
|
||
|
|
extractStream(consume(StreamPlan), StreamPlan, QueryAttr) :-
|
||
|
|
extractQueryAttr(StreamPlan, QueryAttr).
|
||
|
|
|
||
|
|
% NVK ADDED NR
|
||
|
|
% May still fail for tables or arel's with only one column.
|
||
|
|
extractStream(aconsume(project(StreamPlan, QueryAttr)), StreamPlan, QueryAttr).
|
||
|
|
extractStream(aconsume(StreamPlan), StreamPlan, QueryAttr) :-
|
||
|
|
extractQueryAttr(StreamPlan, QueryAttr).
|
||
|
|
% NVK ADDED NR END
|
||
|
|
|
||
|
|
extractQueryAttr(project(_, QueryAttr), QueryAttr).
|
||
|
|
|
||
|
|
extractQueryAttr(Stream, QueryAttr) :-
|
||
|
|
Stream =.. [filter, Stream2, _],
|
||
|
|
extractQueryAttr(Stream2, QueryAttr).
|
||
|
|
|
||
|
|
extractQueryAttr(_, _) :- !, fail.
|
||
|
|
|
||
|
|
/*
|
||
|
|
18.1.3 Translation of nested queries
|
||
|
|
|
||
|
|
Translate a subquery into an execution plan. Includes handling of
|
||
|
|
correlated predicates.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
% case subquery of selection predicate
|
||
|
|
subquery_to_plan(Query, Plan3, T) :-
|
||
|
|
ground(Query),
|
||
|
|
Query =.. [from, _, Where],
|
||
|
|
Where =.. [where, Rels, _],
|
||
|
|
removeCorrelatedPreds(Query, Query1, Preds), !,
|
||
|
|
ground(Query1),
|
||
|
|
dm(subqueryDebug, ['\nQuery1: ', Query1,
|
||
|
|
'\nCorrelatedPreds: ', Preds]),
|
||
|
|
Query1 =.. [from, Select1, Where1],
|
||
|
|
transformAttrExpr(Select1, T, 2, Select2, []),
|
||
|
|
Query2 =..[from, Select2, Where1],
|
||
|
|
descendLevel,
|
||
|
|
%putOptimizerState, % NVK ADDED
|
||
|
|
queryToPlan(Query2, Plan, _), !,
|
||
|
|
%restoreOptimizerState, % NVK ADDED
|
||
|
|
ascendLevel,
|
||
|
|
dm(subqueryDebug, ['\nPlan: ', Plan]),
|
||
|
|
transformCorrelatedPreds(Rels, T, Preds, Preds2),
|
||
|
|
addCorrelatedPreds(Plan, Plan2, Preds2),
|
||
|
|
dm(subqueryDebug, ['\nPlan2: ', Plan2]),
|
||
|
|
transformPlan(Plan2, Plan3),
|
||
|
|
dm(subqueryDebug, ['\nPlan3: ', Plan3]).
|
||
|
|
|
||
|
|
subquery_to_plan(Query, Plan2, _) :-
|
||
|
|
ground(Query),
|
||
|
|
descendLevel,
|
||
|
|
queryToPlan(Query, Plan, _), !,
|
||
|
|
ascendLevel,
|
||
|
|
ensure(transformPlan(Plan, Plan2)),
|
||
|
|
dm(subqueryDebug, ['\nPlan2: ', Plan2]).
|
||
|
|
|
||
|
|
% case subquery of join predicate, apply both names
|
||
|
|
subquery_to_plan(Query, Plan3, T1, T2) :-
|
||
|
|
ground(Query),
|
||
|
|
Query =.. [from, _, Where],
|
||
|
|
Where =.. [where, Rels, _],
|
||
|
|
removeCorrelatedPreds(Query, Query1, Preds), !,
|
||
|
|
ground(Query1),
|
||
|
|
dm(subqueryDebug, ['\nQuery1: ', Query1,
|
||
|
|
'\nCorrelatedPreds: ', Preds]),
|
||
|
|
Query1 =.. [from, Select1, Where1],
|
||
|
|
transformAttrExpr(Select1, T1, 2, Select2, []),
|
||
|
|
transformAttrExpr(Select2, T2, 1, Select3, []),
|
||
|
|
Query2 =..[from, Select3, Where1],
|
||
|
|
descendLevel,
|
||
|
|
queryToPlan(Query2, Plan, _), !,
|
||
|
|
ascendLevel,
|
||
|
|
dm(subqueryDebug, ['\nPlan: ', Plan]),
|
||
|
|
transformCorrelatedPreds(Rels, T1, Preds, Preds2),
|
||
|
|
transformCorrelatedPreds(Rels, T2, Preds2, Preds3),
|
||
|
|
addCorrelatedPreds(Plan, Plan2, Preds3),
|
||
|
|
dm(subqueryDebug, ['\nPlan2: ', Plan2]),
|
||
|
|
transformPlan(Plan2, Plan3),
|
||
|
|
dm(subqueryDebug, ['\nPlan3: ', Plan3]).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
18.1.4 Translation of a subquery into executable syntax.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
subquery_to_atom(Query, QueryAtom) :-
|
||
|
|
ground(Query),
|
||
|
|
subquery_to_plan(Query, Plan),
|
||
|
|
plan_to_atom(Plan, QueryAtom),
|
||
|
|
dm(subqueryDebug, ['\nQueryAtom: ', QueryAtom]).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Expressions over attributes
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
% case atomic value
|
||
|
|
subquery_expr_to_plan(Expr, _, Expr) :-
|
||
|
|
atomic(Expr).
|
||
|
|
|
||
|
|
% case attribute value, applies renaming
|
||
|
|
subquery_expr_to_plan(attr(A, Arg, Case), _,
|
||
|
|
attribute(T, attrname(attr(A, Arg, Case)))) :-
|
||
|
|
peak(streamRel, rel(Rel, _)),
|
||
|
|
isAttributeOf(A, Rel),
|
||
|
|
peak(streamName, T).
|
||
|
|
|
||
|
|
subquery_expr_to_plan(attr(A, Arg, Case), _,
|
||
|
|
attribute(T, attrname(attr(A, Arg, Case)))) :-
|
||
|
|
peak(streamRel, 2, rel(Rel, _)),
|
||
|
|
isAttributeOf(A, Rel),
|
||
|
|
peak(streamName, 2, T).
|
||
|
|
|
||
|
|
subquery_expr_to_plan(attr(A, Arg, Case), _,
|
||
|
|
attribute(T, attrname(attr(A, Arg, Case)))) :-
|
||
|
|
peak(streamRel, 2, rel(Rel, _)),
|
||
|
|
isAttributeOf(A, Rel),
|
||
|
|
not(peak(streamName, 2, _)),
|
||
|
|
peak(streamName, T).
|
||
|
|
|
||
|
|
% general translation of attribute expression
|
||
|
|
subquery_expr_to_plan(Expr, Param, Expr2) :-
|
||
|
|
transformAttrExpr(Expr, Param, 1, Expr1, []),
|
||
|
|
transformAttrExpr(Expr1, Param, 2, Expr2, []).
|
||
|
|
|
||
|
|
subquery_expr_to_plan(A, B, C) :-
|
||
|
|
my_concat_atom(['Not Implemented'], Msg),
|
||
|
|
throw(error_Internal(subqueries_Expr(A, B, C)::notImplemented::Msg)).
|
||
|
|
|
||
|
|
% NVK ADDED NR
|
||
|
|
subqueryContainsWhere(subquery(_, Query, _)) :-
|
||
|
|
Query =.. [from, _, Where],
|
||
|
|
Where =.. [where, _, _].
|
||
|
|
% NVK ADDED NR END
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Extract query from subquery and put used relations on stack.
|
||
|
|
|
||
|
|
*/
|
||
|
|
extractQuery(subquery(_, Query, [Rel]), Query) :- % NVK MODIFIED NR
|
||
|
|
!,
|
||
|
|
streamRel(Rel).
|
||
|
|
|
||
|
|
extractQuery(subquery(_, Query, [Rel1, Rel2]), Query) :- % NVK MODIFIED NR
|
||
|
|
!,
|
||
|
|
streamRel(Rel1),
|
||
|
|
streamRel(Rel2).
|
||
|
|
|
||
|
|
clearQuery(subquery(_, _, [Rel])) :- % NVK MODIFIED NR
|
||
|
|
!,
|
||
|
|
clearStreamRel(Rel).
|
||
|
|
|
||
|
|
clearQuery(subquery(_, _, [Rel1, Rel2])) :- % NVK MODIFIED NR
|
||
|
|
!,
|
||
|
|
clearStreamRel(Rel1, Rel2).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Translate a list of values into kernel syntax for lists.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
secondo_list_to_atom(CommaList, Result) :-
|
||
|
|
CommaList =.. [(,), X, Xs],
|
||
|
|
plan_to_atom(X, XAtom),
|
||
|
|
secondo_list_to_atom((Xs), XsAtom),
|
||
|
|
my_concat_atom([XAtom, ' ', XsAtom], '', Result),
|
||
|
|
!.
|
||
|
|
|
||
|
|
secondo_list_to_atom(X, Result) :-
|
||
|
|
plan_to_atom(X, Result),
|
||
|
|
!.
|
||
|
|
|
||
|
|
secondo_list_to_atom([], '') :- !.
|
||
|
|
|
||
|
|
% floating point constants
|
||
|
|
subquery_plan_to_atom(Data, Result) :-
|
||
|
|
float(Data),
|
||
|
|
format(atom(Result), '~10f~n', Data).
|
||
|
|
|
||
|
|
% in expression with constant list
|
||
|
|
subquery_plan_to_atom(X, Result) :-
|
||
|
|
X =.. [in, Attr, ValueList],
|
||
|
|
ValueList =.. [(,) | _],
|
||
|
|
constantType(Attr, Type),
|
||
|
|
plan_to_atom(Attr, AttrAtom),
|
||
|
|
secondo_list_to_atom(ValueList, VLAtom),
|
||
|
|
my_concat_atom([AttrAtom,
|
||
|
|
' in [const set(', Type, ') value (', VLAtom, ')]'],
|
||
|
|
Result),
|
||
|
|
!.
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Translation of outerjoin expressions, only binary operators with
|
||
|
|
attributes are currently considered.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
% outerjoin, equi-join case
|
||
|
|
subquery_plan_to_atom(outerjoin(=, JoinAttr1, JoinAttr2), Result) :-
|
||
|
|
plan_to_atom(JoinAttr1, AAtom1),
|
||
|
|
plan_to_atom(JoinAttr2, AAtom2),
|
||
|
|
my_concat_atom([' smouterjoin[', AAtom1, ',', AAtom2, ']'], Result),
|
||
|
|
!.
|
||
|
|
|
||
|
|
% outerjoin, general case
|
||
|
|
subquery_plan_to_atom(outerjoin(Op, attrname(JoinAttr1), attrname(JoinAttr2)),
|
||
|
|
Result) :-
|
||
|
|
( outerjoinCommuted
|
||
|
|
-> Pred =.. [Op, JoinAttr2, JoinAttr1]
|
||
|
|
; Pred =.. [Op, JoinAttr1, JoinAttr2] ),
|
||
|
|
retractall(outerjoinCommuted),
|
||
|
|
consider_Arg2(Pred, Pred2), % transform second arg/3 to arg2/3
|
||
|
|
plan_to_atom(Pred2, PAtom),
|
||
|
|
my_concat_atom([' symmouterjoin[', PAtom, ']'], Result),
|
||
|
|
!.
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
The translation of nested predicates uses a mapping function
|
||
|
|
to implement nested-iteration semantics. Parameter(s) to this
|
||
|
|
function are automaticall renamed. Special handling for subqueries
|
||
|
|
using more than one outer relation is necessary. Such predicates
|
||
|
|
are a form of general join predicate an need access to both streams.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
% case nested predicate is join predicate
|
||
|
|
subquery_plan_to_atom(Pred, Result) :-
|
||
|
|
ground(Pred),
|
||
|
|
isJoinPred(Pred),
|
||
|
|
dm(subqueryDebug, ['\nisJoinPred!\n']),
|
||
|
|
Pred =.. [Op, Attr, Query],
|
||
|
|
extractQuery(Query, Query1),
|
||
|
|
isSubqueryOp(Op),
|
||
|
|
Query1 =.. [from | _],
|
||
|
|
dm(subqueryDebug, ['\n',
|
||
|
|
'\nisJoinPred\n\n\t']),
|
||
|
|
dc(subqueryDebug, write_canonical(Pred)),
|
||
|
|
dm(subqueryDebug, ['\nOp: ', Op,
|
||
|
|
'\nAttr: ', Attr,
|
||
|
|
'\nQuery: ', Query1]),
|
||
|
|
newTempRel(T1),
|
||
|
|
streamName(T1),
|
||
|
|
newTempRel(T2),
|
||
|
|
streamName(T2),
|
||
|
|
Query=subquery(SQID, _, _), % NVK ADDED
|
||
|
|
restoreSQID(SQID), % NVK ADDED
|
||
|
|
subquery_to_plan(Query1, QueryPlan, T1, T2),
|
||
|
|
transformAttrExpr(Attr, T1, 1, Attr3, []),
|
||
|
|
transformAttrExpr(Attr3, T2, 2, Attr4, []),
|
||
|
|
ResultPlan =.. [Op, Attr4, QueryPlan],
|
||
|
|
dm(subqueryDebug, ['\nQueryPlan: ', QueryPlan]),
|
||
|
|
plan_to_atom(fun([param(T1, tuple), param(T2, tuple2)], ResultPlan), Result),
|
||
|
|
setSQIDToPrevious(SQID), % NVK ADDED
|
||
|
|
clearStreamName,
|
||
|
|
clearStreamName,
|
||
|
|
clearQuery(Query).
|
||
|
|
|
||
|
|
% case join predicate with not in expression
|
||
|
|
subquery_plan_to_atom(Pred, Result) :-
|
||
|
|
ground(Pred),
|
||
|
|
isJoinPred(Pred),
|
||
|
|
dm(subqueryDebug, ['\nisJoinPred!\n']),
|
||
|
|
Pred =.. [not, Attr, InExpr],
|
||
|
|
InExpr =.. [in, Query],
|
||
|
|
extractQuery(Query, Query1),
|
||
|
|
Query1 =.. [from | _],
|
||
|
|
dm(subqueryDebug, ['\n',
|
||
|
|
'\nisJoinPred\n\n\t']),
|
||
|
|
dc(subqueryDebug, write_canonical(Pred)),
|
||
|
|
dm(subqueryDebug, ['\nAttr: ', Attr,
|
||
|
|
'\nQuery: ', Query1]),
|
||
|
|
newTempRel(T1),
|
||
|
|
streamName(T1),
|
||
|
|
% assert(firstStream(T1)),
|
||
|
|
newTempRel(T2),
|
||
|
|
streamName(T2),
|
||
|
|
Query=subquery(SQID, _, _), % NVK ADDED
|
||
|
|
restoreSQID(SQID), % NVK ADDED
|
||
|
|
subquery_to_plan(Query1, QueryPlan, T1, T2),
|
||
|
|
extractStream(QueryPlan, StreamPlan, QueryAttr),
|
||
|
|
transformAttrExpr(Attr, T1, 1, Attr3, []),
|
||
|
|
transformAttrExpr(Attr3, T2, 2, Attr4, []),
|
||
|
|
ResultPlan =..
|
||
|
|
[in, Attr4, collect_set(projecttransformstream(StreamPlan, QueryAttr))],
|
||
|
|
dm(subqueryDebug, ['\nQueryPlan: ', QueryPlan]),
|
||
|
|
plan_to_atom(fun([param(T1, tuple), param(T2, tuple2)], not(ResultPlan)),
|
||
|
|
Result),
|
||
|
|
setSQIDToPrevious(SQID), % NVK ADDED
|
||
|
|
clearStreamName,
|
||
|
|
clearStreamName,
|
||
|
|
clearQuery(Query).
|
||
|
|
|
||
|
|
% case simple nested predicate with not in
|
||
|
|
subquery_plan_to_atom(Pred, Result) :-
|
||
|
|
ground(Pred),
|
||
|
|
Pred =.. [not, Attr, InExpr],
|
||
|
|
InExpr =.. [in, Query],
|
||
|
|
Pred2 =.. [in, Attr, Query],
|
||
|
|
extractQuery(Query, Query1),
|
||
|
|
Query1 =.. [from | _],
|
||
|
|
dm(subqueryDebug, ['\n\n\n\n',
|
||
|
|
'\nsubquery_plan_to_atom\n\n\t']),
|
||
|
|
dc(subqueryDebug, write_canonical(Pred2)),
|
||
|
|
dm(subqueryDebug, ['\nAttr: ', Attr,
|
||
|
|
'\nQuery: ', Query1, '\n\n\n\n']),
|
||
|
|
% newTempRel(T),
|
||
|
|
Query=subquery(SQID, _, _), % NVK ADDED
|
||
|
|
restoreSQID(SQID), % NVK ADDED
|
||
|
|
newAlias(T),
|
||
|
|
streamName(T),
|
||
|
|
% subquery_to_plan(Query, consume(project(StreamPlan, QueryAttr)), T),
|
||
|
|
subquery_to_plan(Query1, QueryPlan, T),
|
||
|
|
extractStream(QueryPlan, StreamPlan, QueryAttr),
|
||
|
|
dm(subqueryDebug, ['\nStreamPlan: ', StreamPlan]),
|
||
|
|
subquery_expr_to_plan(Attr, T, Attr2),
|
||
|
|
ResultPlan =..
|
||
|
|
[in, Attr2, collect_set(projecttransformstream(StreamPlan, QueryAttr))],
|
||
|
|
plan_to_atom(fun([param(T, tuple)], not(ResultPlan)), Result),
|
||
|
|
setSQIDToPrevious(SQID), % NVK ADDED
|
||
|
|
clearStreamName,
|
||
|
|
clearQuery(Query).
|
||
|
|
|
||
|
|
% case simple nested predicate with in
|
||
|
|
subquery_plan_to_atom(Pred, Result) :-
|
||
|
|
ground(Pred),
|
||
|
|
Pred =.. [in, Attr, Query],
|
||
|
|
extractQuery(Query, Query1),
|
||
|
|
Query1 =.. [from | _],
|
||
|
|
dm(subqueryDebug, ['\n\n\n\n',
|
||
|
|
'\nsubquery_plan_to_atom\n\n\t']),
|
||
|
|
dc(subqueryDebug, write_canonical(Pred)),
|
||
|
|
dm(subqueryDebug, ['\nAttr: ', Attr,
|
||
|
|
'\nQuery: ', Query, '\n\n\n\n']),
|
||
|
|
% newTempRel(T),
|
||
|
|
Query=subquery(SQID, _, _), % NVK ADDED
|
||
|
|
restoreSQID(SQID), % NVK ADDED
|
||
|
|
newAlias(T),
|
||
|
|
streamName(T),
|
||
|
|
% assert(firstStream(T)),
|
||
|
|
subquery_to_plan(Query1, QueryPlan, T),
|
||
|
|
% consume(project(StreamPlan, QueryAttr))
|
||
|
|
extractStream(QueryPlan, StreamPlan, QueryAttr),
|
||
|
|
dm(subqueryDebug, ['\nStreamPlan: ', StreamPlan]),
|
||
|
|
subquery_expr_to_plan(Attr, T, Attr2),
|
||
|
|
ResultPlan =..
|
||
|
|
[in, Attr2, collect_set(projecttransformstream(StreamPlan, QueryAttr))],
|
||
|
|
plan_to_atom(fun([param(T, tuple)], ResultPlan), Result),
|
||
|
|
setSQIDToPrevious(SQID), % NVK ADDED
|
||
|
|
clearStreamName,
|
||
|
|
clearQuery(Query).
|
||
|
|
|
||
|
|
% case simple nested predicate, no aggregation
|
||
|
|
subquery_plan_to_atom(Pred, Result) :-
|
||
|
|
ground(Pred),
|
||
|
|
Pred =.. [Op, Attr, Query],
|
||
|
|
isSubqueryOp(Op),
|
||
|
|
extractQuery(Query, Query1),
|
||
|
|
Query1 =.. [from | _],
|
||
|
|
dm(subqueryDebug, ['\n',
|
||
|
|
'=================',
|
||
|
|
'=================',
|
||
|
|
'=================',
|
||
|
|
'=================',
|
||
|
|
'\nsubquery_plan_to_atom\n\n\t']),
|
||
|
|
dc(subqueryDebug, write_canonical(Pred)),
|
||
|
|
dm(subqueryDebug, ['\nOp: ', Op,
|
||
|
|
'\nAttr: ', Attr,
|
||
|
|
'\nQuery: ', Query1]),
|
||
|
|
Query=subquery(SQID, _, _), % NVK ADDED
|
||
|
|
restoreSQID(SQID), % NVK ADDED
|
||
|
|
newAlias(T),
|
||
|
|
streamName(T),
|
||
|
|
subquery_to_plan(Query1, QueryPlan, T),
|
||
|
|
subquery_expr_to_plan(Attr, T, Attr2),
|
||
|
|
dm(subqueryDebug, ['\nAttr2: ', Attr2]),
|
||
|
|
ResultPlan =.. [Op, Attr2, QueryPlan],
|
||
|
|
plan_to_atom(fun([param(T, tuple)], ResultPlan), Result),
|
||
|
|
setSQIDToPrevious(SQID), % NVK ADDED
|
||
|
|
clearStreamName,
|
||
|
|
clearQuery(Query).
|
||
|
|
|
||
|
|
% case aggregated atttribute expression
|
||
|
|
subquery_plan_to_atom(AttrExpr, Result) :-
|
||
|
|
ground(AttrExpr),
|
||
|
|
AttrExpr =.. [Op, Attr],
|
||
|
|
isAggregationOP(Op),
|
||
|
|
dm(subqueryDebug, ['\nAttr: ', Attr]),
|
||
|
|
Attr =.. [attribute, _, attrname(attr(Attr2, _, _))],
|
||
|
|
dm(subqueryDebug, ['\nAttr: ', Attr,
|
||
|
|
'\nAttr2: ', Attr2]),
|
||
|
|
my_concat_atom([Op, '[', Attr2, ']'], Result).
|
||
|
|
|
||
|
|
% case nested predicate with exists
|
||
|
|
subquery_plan_to_atom(Expr, Result) :-
|
||
|
|
ground(Expr),
|
||
|
|
Expr =.. [exists, Query],
|
||
|
|
% NVK ADDED NR: Pretest with no side effects (unlike extractQuery).
|
||
|
|
subqueryContainsWhere(Query),
|
||
|
|
% NVK ADDED NR END
|
||
|
|
extractQuery(Query, Query1),
|
||
|
|
Query1 =.. [from, _, Where],
|
||
|
|
Where =.. [where | _],
|
||
|
|
removeCorrelatedPreds(Query1, Query2, Preds), !,
|
||
|
|
ground(Query2),
|
||
|
|
dm(subqueryDebug, ['\nQuery2: ', Query2,
|
||
|
|
'\nCorrelatedPreds: ', Preds]),
|
||
|
|
Query=subquery(SQID, _, _), % NVK ADDED
|
||
|
|
restoreSQID(SQID), % NVK ADDED
|
||
|
|
newAlias(T),
|
||
|
|
streamName(T),
|
||
|
|
subquery_to_plan(Query2, Plan, T),
|
||
|
|
dm(subqueryDebug, ['\nPlan: ', Plan]),
|
||
|
|
transformPreds(Preds, T, 2, Preds2),
|
||
|
|
dm(subqueryDebug, ['\nPreds2: ', Preds2]), !,
|
||
|
|
% NVK MODIFIED NR
|
||
|
|
%addCorrelatedPreds(Plan, consume(Query3), Preds2),
|
||
|
|
addCorrelatedPreds(Plan, Plan2, Preds2),
|
||
|
|
Plan2=..[COp, Query3],
|
||
|
|
member(COp, [consume, aconsume]),
|
||
|
|
% NVK MODIFIED NR END
|
||
|
|
dm(subqueryDebug, ['\nsubquery_plan_to_atom_Query2: ', Query3]),
|
||
|
|
plan_to_atom(fun([param(T, tuple)], =(count(head(Query3, 1)), 1)), Result),
|
||
|
|
setSQIDToPrevious(SQID), % NVK ADDED NR
|
||
|
|
dm(subqueryDebug, ['\nsubquery_plan_to_atom_QueryAtom: ', Result]),
|
||
|
|
clearStreamName,
|
||
|
|
clearQuery(Query).
|
||
|
|
|
||
|
|
/*
|
||
|
|
NVK ADDED NR
|
||
|
|
case nested predicate with exists
|
||
|
|
Case as above, but without a where clause.
|
||
|
|
|
||
|
|
Note that this is currentliy only usefull if in the from clause a arel relation appears due to the optimization limitations.
|
||
|
|
|
||
|
|
Imlemented exemplarily for the exists operators. This subquery\_plan\_to\_atom thing should be generalized in some way...
|
||
|
|
|
||
|
|
*/
|
||
|
|
subquery_plan_to_atom(Expr, Result) :-
|
||
|
|
optimizerOption(nestedRelations),
|
||
|
|
ground(Expr),
|
||
|
|
Expr =.. [exists, Query],
|
||
|
|
extractQuery(Query, Query1),
|
||
|
|
Query1 =.. [from, _, Where],
|
||
|
|
\+ Where =.. [where | _],
|
||
|
|
Query1=Query2,
|
||
|
|
ground(Query2),
|
||
|
|
dm(subqueryDebug, ['\nQuery2: ', Query2]),
|
||
|
|
Query=subquery(SQID, _, _),
|
||
|
|
restoreSQID(SQID),
|
||
|
|
newAlias(T),
|
||
|
|
streamName(T),
|
||
|
|
subquery_to_plan(Query2, Plan, T),
|
||
|
|
dm(subqueryDebug, ['\nPlan: ', Plan]),
|
||
|
|
Plan=Plan2,
|
||
|
|
Plan2=..[COp, Query3],
|
||
|
|
member(COp, [consume, aconsume]),
|
||
|
|
dm(subqueryDebug, ['\nsubquery_plan_to_atom_Query2: ', Query3]),
|
||
|
|
plan_to_atom(fun([param(T, tuple)], =(count(head(Query3, 1)), 1)), Result),
|
||
|
|
dm(subqueryDebug, ['\nsubquery_plan_to_atom_QueryAtom: ', Result]),
|
||
|
|
setSQIDToPrevious(SQID),
|
||
|
|
clearStreamName,
|
||
|
|
clearQuery(Query).
|
||
|
|
% NVK ADDED NR END
|
||
|
|
|
||
|
|
|
||
|
|
% case nested predicate with not exists
|
||
|
|
subquery_plan_to_atom(not(Expr), Result) :-
|
||
|
|
ground(Expr),
|
||
|
|
Expr =.. [exists, Query],
|
||
|
|
extractQuery(Query, Query1),
|
||
|
|
Query1 =.. [from, _, Where],
|
||
|
|
Where =.. [where | _],
|
||
|
|
removeCorrelatedPreds(Query1, Query2, Preds), !,
|
||
|
|
ground(Query2),
|
||
|
|
dm(subqueryDebug, ['\nQuery2: ', Query2,
|
||
|
|
'\nCorrelatedPreds: ', Preds]),
|
||
|
|
Query=subquery(SQID, _, _), % NVK ADDED
|
||
|
|
restoreSQID(SQID), % NVK ADDED
|
||
|
|
newAlias(T),
|
||
|
|
streamName(T),
|
||
|
|
subquery_to_plan(Query2, Plan, T),
|
||
|
|
dm(subqueryDebug, ['\nPlan: ', Plan]),
|
||
|
|
transformPreds(Preds, T, 2, Preds2),
|
||
|
|
dm(subqueryDebug, ['\nPreds2: ', Preds2]), !,
|
||
|
|
% NVK MODIFIED NR
|
||
|
|
%addCorrelatedPreds(Plan, consume(Query3), Preds2),
|
||
|
|
addCorrelatedPreds(Plan, Plan2, Preds2),
|
||
|
|
Plan2=..[COp, Query3],
|
||
|
|
member(COp, [consume, aconsume]),
|
||
|
|
% NVK MODIFIED NR END
|
||
|
|
dm(subqueryDebug, ['\nsubquery_plan_to_atom_Query2: ', Query3]),
|
||
|
|
plan_to_atom(fun([param(T, tuple)], not(=(count(head(Query3, 1)), 1))),
|
||
|
|
Result),
|
||
|
|
setSQIDToPrevious(SQID), % NVK ADDED NR
|
||
|
|
dm(subqueryDebug, ['\nsubquery_plan_to_atom_Result: ', Result]),
|
||
|
|
clearStreamName,
|
||
|
|
clearQuery(Query).
|
||
|
|
|
||
|
|
% flag symmjoin with nested predicate as join predicate
|
||
|
|
subquery_plan_to_atom(symmjoin(Arg1, Arg2, Pred), Result) :-
|
||
|
|
isSubqueryPred1(Pred),
|
||
|
|
not(isJoinPred(Pred)),
|
||
|
|
dm(subqueryDebug, ['\nsymmjoin: ', Pred]),
|
||
|
|
assert(isJoinPred(Pred)),
|
||
|
|
joinRels(Arg1, Arg2),
|
||
|
|
plan_to_atom(symmjoin(Arg1, Arg2, Pred), Result),
|
||
|
|
dm(subqueryDebug, ['n\symmjoin succeeded']),
|
||
|
|
retractall(isJoinPred(Pred)).
|
||
|
|
|
||
|
|
% case rightrange with nested predicate
|
||
|
|
subquery_plan_to_atom(rightrange(Arg1, Arg2, Query), Result) :-
|
||
|
|
extractQuery(Query, Query1),
|
||
|
|
Query1 =.. [from | _],
|
||
|
|
dm(subqueryDebug, ['\nrightrange: ', Query]),
|
||
|
|
Query=subquery(SQID, _, _), % NVK ADDED
|
||
|
|
restoreSQID(SQID), % NVK ADDED
|
||
|
|
subquery_to_plan(Query1, Plan, _),
|
||
|
|
plan_to_atom(rightrange(Arg1, Arg2, Plan), Result),
|
||
|
|
setSQIDToPrevious(SQID). % NVK ADDED NR
|
||
|
|
|
||
|
|
% case leftrange with nested predicate
|
||
|
|
subquery_plan_to_atom(leftrange(Arg1, Arg2, Query), Result) :-
|
||
|
|
extractQuery(Query, Query1),
|
||
|
|
Query1 =.. [from | _],
|
||
|
|
dm(subqueryDebug, ['\nleftrange: ', Query]),
|
||
|
|
Query=subquery(SQID, _, _), % NVK ADDED
|
||
|
|
restoreSQID(SQID), % NVK ADDED
|
||
|
|
subquery_to_plan(Query1, Plan, _),
|
||
|
|
plan_to_atom(rightrange(Arg1, Arg2, Plan), Result),
|
||
|
|
setSQIDToPrevious(SQID). % NVK ADDED NR
|
||
|
|
|
||
|
|
/*
|
||
|
|
NVK ADDED NR
|
||
|
|
The above Prolog predicates are for query predicates, this
|
||
|
|
is for subqueries within the attribute list. It is added in same way as the
|
||
|
|
upper predicates.
|
||
|
|
|
||
|
|
*/
|
||
|
|
subquery_plan_to_atom(SQuery, Result) :-
|
||
|
|
SQuery=subquery(SQID, Query, Rels),
|
||
|
|
ground(Query),
|
||
|
|
removeCorrelatedPreds(Query, Query2, Preds), !,
|
||
|
|
restoreSQID(SQID),
|
||
|
|
newAlias(T),
|
||
|
|
streamName(T),
|
||
|
|
subquery_to_plan(Query2, QueryPlan, T),
|
||
|
|
|
||
|
|
transformPreds(Preds, T, 2, Preds2),
|
||
|
|
dm(subqueryDebug, ['\nPreds2: ', Preds2]), !,
|
||
|
|
addCorrelatedPreds(QueryPlan, Plan2, Preds2),
|
||
|
|
|
||
|
|
plan_to_atom(fun([param(T, tuple)], Plan2), Result),
|
||
|
|
setSQIDToPrevious(SQID),
|
||
|
|
clearStreamName,
|
||
|
|
(Rels \= [] ->
|
||
|
|
clearQuery(subquery(SQID, Query, Rels))
|
||
|
|
;
|
||
|
|
true
|
||
|
|
).
|
||
|
|
|
||
|
|
subquery_plan_to_atom(SQuery, Result) :-
|
||
|
|
SQuery=..[subquery|_],
|
||
|
|
throw(error_Internal(subquery_subquery_plan_to_atom(SQuery, Result)::failed)).
|
||
|
|
% NVK ADDED NR END
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Translation of the predicates of a subquery. The following predicates
|
||
|
|
are needed, to translate the correlated predicates of a nested query.
|
||
|
|
|
||
|
|
*/
|
||
|
|
% case standard predicate, no special handling necessary.
|
||
|
|
subquerypred_to_atom(Pred, Result) :-
|
||
|
|
ground(Pred),
|
||
|
|
plan_to_atom(Pred, Result),
|
||
|
|
dm(subqueryDebug, ['\nNormalPred: ', Pred,
|
||
|
|
'\nNormalResult: ', Result]).
|
||
|
|
|
||
|
|
subquerypred_to_atom([], []).
|
||
|
|
|
||
|
|
% case selection predicate
|
||
|
|
subquerypred_to_atom(pr(P, _), Result) :-
|
||
|
|
subquerypred_to_atom(P, Result).
|
||
|
|
|
||
|
|
% case join predicate
|
||
|
|
subquerypred_to_atom(pr(P, _, _), Result) :-
|
||
|
|
subquerypred_to_atom(P, Result).
|
||
|
|
|
||
|
|
% case list of predicates
|
||
|
|
subquerypred_to_atom([ Pred | Rest ], Atom) :-
|
||
|
|
ground(Pred),
|
||
|
|
ground(Rest),
|
||
|
|
dm(subqueryDebug, ['\nSubqueryPred: ', Pred]),
|
||
|
|
subquerypred_to_atom(Pred, PredAtom),
|
||
|
|
dm(subqueryDebug, ['\nPredAtom: ', PredAtom]),
|
||
|
|
subquerypred_to_atom(Rest, RestAtom),
|
||
|
|
dm(subqueryDebug, ['\nRestAtom: ', RestAtom]),
|
||
|
|
(( RestAtom = [], PredAtom = Atom )
|
||
|
|
; my_concat_atom([PredAtom, RestAtom], Atom)).
|
||
|
|
|
||
|
|
% correlated predicate
|
||
|
|
subquerypred_to_atom(Pred, PredAtom) :-
|
||
|
|
ground(Pred),
|
||
|
|
not(is_list(Pred)),
|
||
|
|
Pred =.. [ Op, Attr1, Attr2 ],
|
||
|
|
Pred2 =.. [Op, attribute(var1, attrname(Attr1)), Attr2],
|
||
|
|
plan_to_atom(Pred2, Pred2Atom),
|
||
|
|
my_concat_atom(['filter[', Pred2Atom, ']'], PredAtom).
|
||
|
|
|
||
|
|
subquerySelectivity([]).
|
||
|
|
|
||
|
|
subquerySelectivity(Pred) :-
|
||
|
|
not(is_list(Pred)),
|
||
|
|
selectivity(Pred, _).
|
||
|
|
|
||
|
|
subquerySelectivity([ Pred | Rest ]) :-
|
||
|
|
subquerySelectivity(Pred),
|
||
|
|
subquerySelectivity(Rest).
|
||
|
|
|
||
|
|
subquerySelectivity(pr(Pred, Rel1, Rel2), Sel, CalcPET, ExpPET) :-
|
||
|
|
isSubqueryPred1(Pred),
|
||
|
|
selectivity(pr(Pred, Rel1, Rel2), Sel, CalcPET, ExpPET),
|
||
|
|
retractall(firstStream(_)).
|
||
|
|
|
||
|
|
subquerySelectivity(pr(Pred, Rel), Sel, CalcPET, ExpPET) :-
|
||
|
|
isSubqueryPred1(Pred),
|
||
|
|
selectivity(pr(Pred, Rel), Sel, CalcPET, ExpPET),
|
||
|
|
retractall(firstStream(_)).
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Translation of nested queries in the from-clause if there are no
|
||
|
|
predicates in the outer query.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
subqueryToStream(Query orderby OrderAttrs, Stream4, Cost) :-
|
||
|
|
subqueryToStream1(Query, OrderAttrs, Stream4, Cost).
|
||
|
|
|
||
|
|
subqueryToStream(Query, Stream4, Cost) :-
|
||
|
|
subqueryToStream1(Query, [], Stream4, Cost).
|
||
|
|
|
||
|
|
% case simple query no groupby, no predicates
|
||
|
|
subqueryToStream1(Select from (Subquery) as _, Attrs, Stream4, Cost) :-
|
||
|
|
translate1(Subquery, SubStream, SubSelect, Update, Cost),
|
||
|
|
dm(subqueryDebug, ['\nSubStream: ', SubStream,
|
||
|
|
'\nSubSelect: ', SubSelect]),
|
||
|
|
selectClause(SubSelect, Extend, Project, Rdup),
|
||
|
|
dm(subqueryDebug, ['\nExtend: ', Extend,
|
||
|
|
'\nProject: ', Project,
|
||
|
|
'\nRdup: ', Rdup]),
|
||
|
|
finish2(SubStream, Extend, Project, Rdup, [], Stream2),
|
||
|
|
dm(subqueryDebug, ['\nStream2: ', Stream2]),
|
||
|
|
selectClause(Select, Extend2, Project2, Rdup2),
|
||
|
|
dm(subqueryDebug, ['\nExtend2: ', Extend2,
|
||
|
|
'\nProject2: ', Project2,
|
||
|
|
'\nRdup2: ', Rdup2]),
|
||
|
|
finish2(Stream2, Extend2, Project2, Rdup2, Attrs, Stream3),
|
||
|
|
dm(subqueryDebug, ['\nStream3: ', Stream3]),
|
||
|
|
finishUpdate(Update, Stream3, Stream4),
|
||
|
|
dm(subqueryDebug, ['\nStream4: ', Stream4]),
|
||
|
|
!.
|
||
|
|
|
||
|
|
% case simple query with groupby
|
||
|
|
subqueryToStream1(SelectClause from (Subquery) as _ groupby GroupAttrs, Attrs,
|
||
|
|
Stream5,
|
||
|
|
Cost) :-
|
||
|
|
translate1(Subquery, SubStream, SubSelect, Update, Cost),
|
||
|
|
dm(subqueryDebug, ['\nSubStream: ', SubStream,
|
||
|
|
'\nSubSelect: ', SubSelect]),
|
||
|
|
selectClause(SubSelect, Extend, Project, Rdup),
|
||
|
|
dm(subqueryDebug, ['\nExtend: ', Extend,
|
||
|
|
'\nProject: ', Project,
|
||
|
|
'\nRdup: ', Rdup]),
|
||
|
|
finish2(SubStream, Extend, Project, Rdup, [], Stream2),
|
||
|
|
dm(subqueryDebug, ['\nStream2: ', Stream2]),
|
||
|
|
makeList(GroupAttrs, Attrs2),
|
||
|
|
attrnames(Attrs2, AttrNamesGroup),
|
||
|
|
attrnamesSort(Attrs2, AttrNamesSort),
|
||
|
|
SelectClause = (select Select),
|
||
|
|
dm(subqueryDebug, ['\nSelect: ', Select]),
|
||
|
|
makeList(Select, SelAttrs),
|
||
|
|
dm(subqueryDebug, ['\nSelAttrs: ', SelAttrs]),
|
||
|
|
%write('SelAttrs:'), write(SelAttrs), nl,
|
||
|
|
translateFields(SelAttrs, Attrs2, Fields, Select2,_,_),
|
||
|
|
Stream3 = groupby(sortby(Stream2, AttrNamesSort), AttrNamesGroup, Fields),
|
||
|
|
selectClause(select Select2, Extend2, Project2, Rdup2),
|
||
|
|
dm(subqueryDebug, ['\nExtend2: ', Extend2,
|
||
|
|
'\nProject2: ', Project2,
|
||
|
|
'\nRdup2: ', Rdup2]),
|
||
|
|
finish2(Stream3, Extend2, Project2, Rdup2, Attrs, Stream4),
|
||
|
|
dm(subqueryDebug, ['\nStream4: ', Stream4]),
|
||
|
|
finishUpdate(Update, Stream4, Stream5),
|
||
|
|
% throw(error_SQL(subqueries_transformNestedPredicate::tRel1Error)),
|
||
|
|
dm(subqueryDebug, ['\nStream5: ', Stream5]),
|
||
|
|
!.
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Utility Functions
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
:- dynamic(stack/2).
|
||
|
|
|
||
|
|
push(StackName, Var) :-
|
||
|
|
ground(Var),
|
||
|
|
stack(StackName, L),
|
||
|
|
retractall(stack(StackName, _)),
|
||
|
|
assert(stack(StackName, [ Var | L])).
|
||
|
|
|
||
|
|
push(StackName, Var) :-
|
||
|
|
ground(Var),
|
||
|
|
not(stack(StackName, _)),
|
||
|
|
assert(stack(StackName, [ Var ])).
|
||
|
|
|
||
|
|
push(_, _) :-
|
||
|
|
throw(error_SQL(subqueries_push::unknownError::_)).
|
||
|
|
|
||
|
|
pop(StackName, Var) :-
|
||
|
|
stack(StackName, [ Var | L ]),
|
||
|
|
retractall(stack(StackName, _)),
|
||
|
|
assert(stack(StackName, L)).
|
||
|
|
|
||
|
|
peak(StackName, Var) :-
|
||
|
|
stack(StackName, [ Var | _ ]).
|
||
|
|
|
||
|
|
peak(StackName, Depth, Var) :-
|
||
|
|
stack(StackName, L),
|
||
|
|
nth1(Depth, L, Var).
|
||
|
|
|
||
|
|
clear(StackName) :-
|
||
|
|
retractall(stack(StackName, _)).
|
||
|
|
|
||
|
|
printStack(StackName) :-
|
||
|
|
stack(StackName, L),
|
||
|
|
nl, write('Stack '), write(StackName), nl,
|
||
|
|
write_list(L), nl.
|
||
|
|
|
||
|
|
partition(Pred, List, Included, Excluded) :-
|
||
|
|
partition_(List, Pred, Included, Excluded).
|
||
|
|
|
||
|
|
partition_([], _, [], []).
|
||
|
|
partition_([H|T], Pred, Incl, Excl) :-
|
||
|
|
( call(Pred, H)
|
||
|
|
-> Incl = [H|I],
|
||
|
|
partition_(T, Pred, I, Excl)
|
||
|
|
; Excl = [H|E],
|
||
|
|
partition_(T, Pred, Incl, E)
|
||
|
|
).
|
||
|
|
|
||
|
|
subset([], []).
|
||
|
|
|
||
|
|
subset([_|Xs], Ys) :-
|
||
|
|
ground(Xs),
|
||
|
|
subset(Xs, Ys).
|
||
|
|
|
||
|
|
subset([X|Xs], [X|Ys]) :-
|
||
|
|
subset(Xs, Ys).
|
||
|
|
|
||
|
|
:- [subquerytest].
|
||
|
|
:- [tpcdqueries].
|