home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / comp / lang / prolog / 2291 < prev    next >
Encoding:
Text File  |  1992-12-22  |  28.1 KB  |  917 lines

  1. Newsgroups: comp.lang.prolog
  2. Path: sparky!uunet!spool.mu.edu!yale.edu!ira.uka.de!fauern!lrz-muenchen.de!mac_server.cis.uni-muenchen.de!user
  3. From: draxler@cis.uni-muenchen.de (Christoph Draxler)
  4. Subject: Prolog to SQL compiler v.1.1 (part 1/2)
  5. Message-ID: <draxler-221292134855@mac_server.cis.uni-muenchen.de>
  6. Followup-To: comp.lang.prolog
  7. Sender: news@news.lrz-muenchen.de (Mr. News)
  8. Organization: CIS - Centrum fuer Informations- und Sprachverarbeitung
  9. Date: Tue, 22 Dec 1992 12:47:04 GMT
  10. Lines: 905
  11.  
  12. Here it is, just before Christmas: a new version of the Prolog to SQL
  13. compiler. 
  14.  
  15.    New features include:
  16.  
  17.    - a rudimentary type system for consistency checks for comparison
  18.      operations and quoted output of constant strings
  19.  
  20.    - SQL queries may be output on the screen or returned as Prolog atoms
  21.  
  22. Have fun with the compiler (and note: there`s a report with tons of
  23. benchmarks available). I am eager to know of your experiences with the
  24. compiler, so please send me any comments, criticism et al!
  25.  
  26.  
  27. Christoph Draxler
  28. University of Munich
  29. draxler@cis.uni-muenchen.de
  30.  
  31.  
  32. --- CODE BEGINS HERE
  33. -----------------------------------------------------------
  34.  
  35.  
  36.  
  37. %
  38. --------------------------------------------------------------------------------------
  39. %
  40. % This Prolog to SQL compiler may be distributed free of charge provided
  41. that it is
  42. % not used in commercial applications without written consent of the
  43. author, and
  44. % that the copyright notice remains unchanged.
  45. %
  46. %                    (C) Copyright by Christoph Draxler, Munich
  47. %                        Version 1.1 of Dec. 21st 1992
  48. %
  49. % I would like to keep in my hands the further development and distribution
  50. of the
  51. % compiler. This does not mean that I don't want other people to suggest or
  52. even
  53. % implement improvements - quite on the contrary: I greatly appreciate
  54. contributions 
  55. % and if they make sense to me I will incorporate them into the compiler
  56. (with due
  57. % credits given!). 
  58. % For further development of the compiler, address your requests, comments
  59. and
  60. % criticism to the author:
  61. %
  62. %                    Christoph Draxler
  63. %                    CIS Centre for Information and Speech Processing
  64. %                    Ludwig-Maximilians-University Munich
  65. %                    Leopoldstr. 139
  66. %                    D 8000 Munich 40
  67. %                    Tel : ++49 / +89 / 36 40 72
  68. %                    Fax : ++49 / +89 / 361 61 99
  69. %                    Mail: draxler@cis.uni-muenchen.de
  70. %
  71. %
  72. % A report describing the implementation is available upon request from the
  73. % author. 
  74. %
  75. %
  76. % RELEASE INFORMATION
  77. % ===================
  78. %
  79. % Current version is v. 1.1 of Dec. 21st 1992.
  80. %
  81. % - The compiler now features a rudimentary type system (to check the
  82. validity of
  83. %   comparison operations and to quote strings in the output.
  84. % - Furthermore, the compiler now also returns the SQL query as a Prolog
  85. atom 
  86. %   (but may conflict with the maximum length limits for atom names). SQL
  87. queries
  88. %   as atoms are needed in some DB-Interfaces of Prolog.
  89. %
  90. % Version 1.0 Sept. 3 1992
  91. %
  92. --------------------------------------------------------------------------------------
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100.  
  101. %
  102. --------------------------------------------------------------------------------------
  103. %
  104. % Top level predicate translate/3 organizes the compilation and constructs
  105. a
  106. % Prolog term representation of the SQL query. 
  107. %
  108. %
  109. --------------------------------------------------------------------------------------
  110.  
  111.  
  112. translate(ProjectionTerm,DatabaseGoal,SQLQueryTerm):-
  113.    % --- initialize variable identifiers and range variables for relations
  114. -----
  115.    init_gensym(var),
  116.    init_gensym(rel),
  117.  
  118.    % --- tokenize projection term and database goal
  119. ----------------------------
  120.    tokenize_term(DatabaseGoal,TokenDatabaseGoal),
  121.    tokenize_term(ProjectionTerm,TokenProjectionTerm),
  122.  
  123.    % --- lexical analysis: reordering of goals for disjunctive normalized
  124. form -
  125.    disjunction(TokenDatabaseGoal,Disjunction),
  126.  
  127.    % --- code generation
  128. ---------------------------------------------------------------
  129.    query_generation(Disjunction,TokenProjectionTerm,SQLQueryTerm).
  130.  
  131.  
  132.  
  133.  
  134.  
  135. % --- disjunction(Goal,Disjunction)
  136. ----------------------------------------------------
  137. %
  138. % turns original goal into disjunctive normalized form by computing all
  139. conjunctions
  140. % and collecting them in a list
  141. %
  142. %
  143. --------------------------------------------------------------------------------------
  144.  
  145. disjunction(Goal,Disjunction):-
  146.    findall(Conjunction,linearize(Goal,Conjunction),Disjunction).
  147.  
  148.  
  149.  
  150.  
  151. % --- linearize(Goal,ConjunctionList)
  152. --------------------------------------------------
  153. %
  154. % Returns a conjunction of base goals for a complex disjunctive or
  155. conjunctive goal
  156. % Yields several solutions upon backtracking for disjunctive goals
  157. %
  158. %
  159. --------------------------------------------------------------------------------------
  160.  
  161. linearize(((A,B),C),(LinA,(LinB,LinC))):-
  162.    % --- transform left-linear to right-linear conjunction (',' is
  163. associative) ----
  164.    linearize(A,LinA),
  165.    linearize(B,LinB),
  166.    linearize(C,LinC).
  167.  
  168. linearize((A,B),(LinA,LinB)):-
  169.    A \= (_,_),
  170.    % --- make sure A is not a conjunction
  171. ------------------------------------------
  172.    linearize(A,LinA),
  173.    linearize(B,LinB).
  174.  
  175. linearize((A;B),LinA):-
  176.    linearize(A,LinA).
  177.  
  178. linearize((A;B),LinB):-
  179.    linearize(B,LinB).
  180.  
  181. linearize(not A, not LinA):-
  182.    linearize(A,LinA).
  183.  
  184. linearize(Var^A, Var^LinA):-
  185.    linearize(A,LinA).
  186.  
  187. linearize(A,A):-
  188.    A \= (_,_),
  189.    A \= (_;_),
  190.    A \= _^_,
  191.    A \= not(_).
  192.  
  193.  
  194.  
  195.  
  196. % --- tokenize_term(Term,TokenizedTerm)
  197. -------------------------------------------------
  198. %
  199. % If Term is a 
  200. %
  201. %  - variable, then this variable is instantiated with a unique identifier 
  202. %    of the form var(VarId), and TokenizedTerm is bound to the same term
  203. var(VarId). 
  204. %
  205. %  - constant, then TokenizedTerm is bound to const(Term).
  206. %
  207. %  - complex term, then the term is decomposed, its arguments are
  208. tokenized,
  209. %    and TokenizedTerm is bound to the result of the composition of the
  210. original
  211. %    functor and the tokenized arguments.
  212. %
  213. %
  214. --------------------------------------------------------------------------------------
  215.  
  216. tokenize_term(var(VarId),var(VarId)):-
  217.    var(VarId),
  218.    % --- uninstantiated variable: instantiate it with unique identifier.
  219.    gensym(var,VarId).
  220.  
  221. tokenize_term(var(VarId),var(VarId)):-
  222.    nonvar(VarId).
  223.  
  224. tokenize_term(Constant,const(Constant)):-
  225.    nonvar(Constant),
  226.    functor(Constant,_,0).
  227.  
  228. tokenize_term(Term,TokenizedTerm):-
  229.    nonvar(Term),
  230.    Term \= var(_),
  231.    Term \= const(_),
  232.    Term =.. [Functor|Arguments],
  233.    Arguments \= [],
  234.    tokenize_arguments(Arguments,TokenArguments),
  235.    TokenizedTerm =.. [Functor|TokenArguments].
  236.  
  237.  
  238.  
  239. % --- tokenize_arguments(Arguments,TokenizedArguments)
  240. ---------------------------------
  241. %
  242. % organizes tokenization of arguments by traversing list and calling
  243. tokenize_term
  244. % for each element of the list.
  245. %
  246. %
  247. --------------------------------------------------------------------------------------
  248.  
  249. tokenize_arguments([],[]).
  250.  
  251. tokenize_arguments([FirstArg|RestArgs],[TokFirstArg|TokRestArgs]):-
  252.    tokenize_term(FirstArg,TokFirstArg),
  253.    tokenize_arguments(RestArgs,TokRestArgs).
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260.  
  261. % --- query_generation(ListOfConjunctions, ProjectionTerm, ListOfQueries)
  262. -------------- 
  263. %
  264. % For each Conjunction translate the pair (ProjectionTerm,Conjunction) to
  265. an SQL query
  266. % and connect each such query through a UNION-operator to result in the
  267. ListOfQueries.
  268. %
  269. % A Conjunction consists of positive or negative subgoals. Each subgoal is
  270. translated 
  271. % as follows:
  272. %  - the functor of a goal that is not a comparison operation is translated
  273. to
  274. %    a relation name with a range variable
  275. %  - negated goals are translated to NOT EXISTS-subqueries with *
  276. projection
  277. %  - comparison operations are translated to comparison operations in the
  278. WHERE-clause
  279. %  - aggregate function terms are translated to aggregate function
  280. (sub)queries
  281. % The arguments of a goal are translated as follows:
  282. %  - variables of a goal are translated to qualified attributes
  283. %  - variables occurring in several goals are translated to equality
  284. comparisons
  285. %    (equi join) in the WHERE-clause
  286. %  - constant arguments are translated to equality comparisons in the
  287. WHERE-clause
  288. % Special treatment of arithmetic functions:
  289. %  - arithmetic functions are identified through the Prolog is/2 operator
  290. %  - an arithmetic function may contain an unbound variable only on its
  291. left side
  292. %  - the right side of the is/2 operator may consist of 
  293. %    * bound variables (bound through occurrence within a positive database
  294. goal, or 
  295. %      bound through preceeding arithmetic function), or of 
  296. %    * constants (numbers, i.e. integers, reals)
  297. % The following RESTRICTION holds:
  298. %
  299. %  - the binding of variables follows Prolog: variables are bound by
  300. positive base goals
  301. %    and on the left side of the is/2 predicate - comparison operations,
  302. negated goals
  303. %    and right sides of the is/2 predicate do not return variable bindings
  304. and may even 
  305. %    require all arguments to be bound for a safe evaluation.
  306. %
  307. %
  308. --------------------------------------------------------------------------------------
  309.  
  310. query_generation([],_,[]).
  311.  
  312. query_generation([Conjunction|Conjunctions],ProjectionTerm,[Query|Queries]):-
  313.    projection_term_variables(ProjectionTerm,InitDict),
  314.    translate_conjunction(Conjunction,SQLFrom,SQLWhere,InitDict,Dict),
  315.    translate_projection(ProjectionTerm,Dict,SQLSelect),
  316.    Query = query(SQLSelect,SQLFrom,SQLWhere),
  317.    query_generation(Conjunctions,ProjectionTerm,Queries).
  318.  
  319.  
  320.  
  321. % --- translate_goal(Goal,SQLFrom,SQLWhere,Dict,NewDict)
  322. -------------------------------
  323. %
  324. % translates a
  325. %
  326. %   - positive database goal to the associated FROM- and WHERE clause of an
  327. SQL query
  328. %   - a negated goal to a negated existential subquery
  329. %   - an arithmetic goal to an arithmetic expression or an aggregate
  330. function query
  331. %   - a comparison goal to a comparison expression
  332. %   - a negated comparison goal to a comparison expression with the
  333. opposite comparison
  334. %     operator
  335. %
  336. %
  337. --------------------------------------------------------------------------------------
  338.  
  339. translate_goal(SimpleGoal,[SQLFrom],SQLWhere,Dict,NewDict):-
  340.    % --- positive goal binds variables - these bindings are held in the
  341. dictionary -----
  342.    functor(SimpleGoal,Functor,Arity),
  343.    translate_functor(Functor,Arity,SQLFrom),
  344.    SimpleGoal =.. [Functor|Arguments],
  345.    translate_arguments(Arguments,SQLFrom,1,SQLWhere,Dict,NewDict).
  346.  
  347. translate_goal(Result is Expression,[],SQLWhere,Dict,NewDict):-
  348.    translate_arithmetic_function(Result,Expression,SQLWhere,Dict,NewDict).
  349.  
  350. translate_goal(not NegatedGoals,[],SQLNegatedSubquery,Dict,Dict):-
  351.    % --- negated goals do not bind variables - hence Dict is returned
  352. unchanged --------
  353.    functor(NegatedGoals,Functor,_),
  354.    not comparison(Functor,_),
  355.    translate_conjunction(NegatedGoals,SQLFrom,SQLWhere,Dict,_),
  356.    SQLNegatedSubquery =
  357. [negated_existential_subquery([*],SQLFrom,SQLWhere)].
  358.  
  359. translate_goal(not ComparisonGoal,[],SQLCompOp,Dict,Dict):-
  360.    % --- comparison operations do not bind variables - Dict is returned
  361. unchanged ------
  362.    ComparisonGoal =.. [ComparisonOperator,LeftArg,RightArg],
  363.    comparison(ComparisonOperator,SQLOperator),
  364.    negated_comparison(SQLOperator,SQLNegOperator),
  365.    translate_comparison(LeftArg,RightArg,SQLNegOperator,Dict,SQLCompOp).
  366.  
  367. translate_goal(ComparisonGoal,[],SQLCompOp,Dict,Dict):-
  368.    % --- comparison operations do not bind variables - Dict is returned
  369. unchanged ------
  370.    ComparisonGoal =.. [ComparisonOperator,LeftArg,RightArg],
  371.    comparison(ComparisonOperator,SQLOperator),
  372.    translate_comparison(LeftArg,RightArg,SQLOperator,Dict,SQLCompOp).
  373.  
  374.  
  375.  
  376.  
  377. % --- translate_conjunction(Conjunction,SQLFrom,SQLWhere,Dict,NewDict)
  378. -----------------
  379. % translates a conjunction of goals (represented as a list of goals
  380. preceeded by 
  381. % existentially quantified variables) to FROM- and WHERE-clause of an SQL
  382. query.  
  383. % A dictionary containing the associated SQL table and attribute names is
  384. built up
  385. % as an accumulator pair (arguments Dict and NewDict)
  386. %
  387. %
  388. --------------------------------------------------------------------------------------
  389.  
  390. translate_conjunction(var(VarId)^Goal,SQLFrom,SQLWhere,Dict,NewDict):-
  391.    % --- add info on existentially quantified variables to dictionary here
  392. -------------
  393.    add_to_dictionary(VarId,_,_,_,existential,Dict,TmpDict),
  394.    translate_conjunction(Goal,SQLFrom,SQLWhere,TmpDict,NewDict).
  395.  
  396. translate_conjunction(Goal,SQLFrom,SQLWhere,Dict,NewDict):-
  397.    Goal \= (_,_),
  398.    translate_goal(Goal,SQLFrom,SQLWhere,Dict,NewDict).
  399.  
  400. translate_conjunction((Goal,Conjunction),SQLFrom,SQLWhere,Dict,NewDict):-
  401.    translate_goal(Goal,FromBegin,WhereBegin,Dict,TmpDict),
  402.    translate_conjunction(Conjunction,FromRest,WhereRest,TmpDict,NewDict),
  403.    append(FromBegin,FromRest,SQLFrom),
  404.    append(WhereBegin,WhereRest,SQLWhere).
  405.  
  406.  
  407.  
  408.  
  409.  
  410. % ---
  411. translate_arithmetic_function(Result,Expression,SQLWhere,Dict,NewDict)
  412. -----------
  413. %
  414. % Arithmetic functions (left side of is/2 operator is bound to value of
  415. expression on
  416. % right side) may be called with either
  417. %
  418. % - Result unbound: then Result is bound to the value of the evaluation of
  419. Expression
  420. % - Result bound: then an equality condition is returned between the value
  421. of Result
  422. %   and the value of the evaluation of Expression.
  423. %
  424. % Only the equality test shows up in the WHERE clause of an SQLquery.
  425. %
  426. %
  427. --------------------------------------------------------------------------------------
  428.  
  429. translate_arithmetic_function(var(VarId),Expression,[],Dict,NewDict):-
  430.    % assigment of value of arithmetic expression to variable - does not
  431.    % show up in WHERE-part, but expression corresponding to
  432.    % variable must be stored in Dict for projection translation
  433.  
  434.    evaluable_expression(Expression,Dict,ArithExpression,Type),
  435.    add_to_dictionary(VarId,is,ArithExpression,Type,all,Dict,NewDict).
  436.  
  437.  
  438. translate_arithmetic_function(var(VarId),Expression,ArithComparison,Dict,Dict):-
  439.    % --- test whether left side evaluates to right side: return equality
  440. comparison ----
  441.    % Left side consists of qualified attribute, i.e. range variable must
  442. not be
  443.    % arithmetic operator is/2 
  444.  
  445.    lookup(VarId,Dict,PrevRangeVar,PrevAtt,PrevType),
  446.    not (PrevRangeVar = is),
  447.  
  448.    % test whether type of attribute is numeric - if not, there's no sense
  449. in 
  450.    % continuing the translation
  451.  
  452.    type_compatible(PrevType,number),
  453.    evaluable_expression(Expression,Dict,ArithExpression,ExprType),
  454.    type_compatible(ExprType,number),
  455.    ArithComparison = [comp(att(PrevRangeVar,PrevAtt),'=',ArithExpression)].
  456.  
  457.  
  458. translate_arithmetic_function(var(VarId),Expression,ArithComparison,Dict,Dict):-
  459.    % --- test whether left side evaluates to right side: return equality
  460. comparison ----
  461.    % Left side consists of arithmetic expression, i.e. VarId is stored in
  462. Dict as 
  463.    % belonging to arithmetic expression which is expressed as
  464. RangeVar-argument 
  465.    % of lookup returning is/2. Type information is implicit through the
  466. is/2 functor
  467.  
  468.    lookup(VarId,Dict,is,LeftExpr,Type),
  469.    type_compatible(Type,number),
  470.    evaluable_expression(Expression,Dict,RightExpr,ExprType),
  471.    type_compatible(ExprType,number),
  472.    ArithComparison = [comp(LeftExpr,'=',RightExpr)].
  473.  
  474.  
  475. translate_arithmetic_function(const(Constant),Expression,ArithComparison,Dict,Dict):-
  476.    % --- is/2 used to test whether left side evaluates to right side
  477. -------------------
  478.    get_type(const(Constant),ConstantType),
  479.    type_compatible(ConstantType,number),
  480.    evaluable_expression(Expression,Dict,ArithExpression,ExprType),
  481.    type_compatible(ExprType,number),
  482.    ArithComparison = [comp(const(Constant),'=',ArithExpression)].
  483.  
  484.  
  485.  
  486. % --- translate_comparison(LeftArg,RightArg,CompOp,Dict,SQLComparison)
  487. ---------
  488. %
  489. % translates the left and right arguments of a comparison term into the
  490. % appropriate comparison operation in SQL. The result type of each 
  491. % argument expression is checked for type compatibility
  492. %
  493. %
  494. ------------------------------------------------------------------------------
  495.  
  496. translate_comparison(LeftArg,RightArg,CompOp,Dict,Comparison):-
  497.    evaluable_expression(LeftArg,Dict,LeftTerm,LeftArgType),
  498.    evaluable_expression(RightArg,Dict,RightTerm,RightArgType),
  499.    type_compatible(LeftArgType,RightArgType),
  500.    Comparison = [comp(LeftTerm,CompOp,RightTerm)].
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507.  
  508. % --- translate_functor(Functor,QualifiedTableName)
  509. ------------------------------------
  510. %
  511. % translate_functor searches for the matching relation table name for
  512. % a given functor and creates a unique range variable to result in
  513. % a unique qualified relation table name.
  514. %
  515. %
  516. --------------------------------------------------------------------------------------
  517.  
  518. translate_functor(Functor,Arity,rel(TableName,RangeVariable)):-
  519.    relation(Functor,Arity,TableName),
  520.    gensym(rel,RangeVariable).
  521.  
  522.  
  523.  
  524.  
  525. % --- translate_arguments(Arguments,RelTable,ArgPos,Conditions,Dict)
  526. -------------------
  527. %
  528. % translate_arguments organizes the translation of term arguments. One
  529. % term argument after the other is taken from the list of term arguments
  530. % until the list is exhausted. 
  531. %
  532. %
  533. --------------------------------------------------------------------------------------
  534.  
  535. translate_arguments([],_,_,[],Dict,Dict).
  536.  
  537. translate_arguments([Arg|Args],SQLTable,Position,SQLWhere,Dict,NewDict):-
  538.    translate_argument(Arg,SQLTable,Position,Where,Dict,TmpDict),
  539.    NewPosition is Position + 1,
  540.   
  541. translate_arguments(Args,SQLTable,NewPosition,RestWhere,TmpDict,NewDict),
  542.    append(Where,RestWhere,SQLWhere).
  543.  
  544.  
  545.  
  546.  
  547. % --- translate_argument(Argument,RelTable,Position,Condition,Dict)
  548. --------------------
  549. %
  550. % The first occurrence of a variable leads to its associated SQL attribute
  551. information
  552. % to be recorded in the Dict. Any further occurrence creates an equi-join
  553. condition 
  554. % between the current attribute and the previously recorded attribute.
  555. % Constant arguments always translate to equality comparisons between an
  556. attribute and 
  557. % the constant value.
  558. %
  559. %
  560. --------------------------------------------------------------------------------------
  561.  
  562. translate_argument(var(VarId),rel(SQLTable,RangeVar),Position,[],Dict,NewDict):-
  563.    attribute(Position,SQLTable,Attribute,Type),
  564.    add_to_dictionary(VarId,RangeVar,Attribute,Type,all,Dict,NewDict).
  565.  
  566. translate_argument(var(VarId),rel(SQLTable,RangeVar),Position,AttComparison,Dict,Dict):-
  567.    % --- Variable occurred previously - retrieve first occurrence data from
  568. dictionary -
  569.    lookup(VarId,Dict,PrevRangeVar,PrevAtt,PrevType),
  570.    attribute(Position,SQLTable,Attribute,Type),
  571.    type_compatible(PrevType,Type),
  572.    AttComparison =
  573. [comp(att(RangeVar,Attribute),=,att(PrevRangeVar,PrevAtt))].
  574.  
  575. translate_argument(const(Constant),rel(SQLTable,RangeVar),Position,ConstComparison,Dict,Dict):-
  576.    % --- Equality comparison of constant value and attribute in table
  577. ------------------
  578.    attribute(Position,SQLTable,Attribute,Type),
  579.    get_type(const(Constant),ConstType),
  580.    type_compatible(ConstType,Type),
  581.    ConstComparison = [comp(att(RangeVar,Attribute),=,const(Constant))].
  582.  
  583.  
  584.  
  585.  
  586.  
  587. % --- projection_term_variables(ProjectionTerm,Dict)
  588. -----------------------------------
  589. %
  590. % extracts all variables from the ProjectionTerm and places them into the
  591. % Dict as a dict/4 term with their Identifier, a non instantiated RangeVar
  592. and 
  593. % Attribute argument, and the keyword existential for the type of
  594. quantification
  595. %
  596. %
  597. --------------------------------------------------------------------------------------
  598.  
  599. projection_term_variables(const(_),[]).
  600.  
  601. projection_term_variables(var(VarId),[dict(VarId,_,_,existential)]).
  602.  
  603. projection_term_variables(ProjectionTerm,ProjectionTermVariables):-
  604.    ProjectionTerm =.. [Functor|ProjectionTermList],
  605.    not (Functor = var),
  606.    not (ProjectionTermList = []),
  607.    projection_list_vars(ProjectionTermList,ProjectionTermVariables).
  608.  
  609.  
  610. projection_list_vars([],[]).
  611. projection_list_vars([var(VarId)|RestArgs],[dict(VarId,_,_,existential)|RestVars]):-
  612.    projection_list_vars(RestArgs,RestVars).
  613. projection_list_vars([const(_)|RestArgs],Vars):-
  614.    projection_list_vars(RestArgs,Vars).
  615.  
  616.  
  617.  
  618.  
  619.  
  620.  
  621. %
  622. --------------------------------------------------------------------------------------
  623. % RESTRICTION! ProjectionTerm underlies the following restrictions:
  624. %
  625. %  - ProjectionTerm must have a functor other than the built-in
  626. %    operators, i.e. ',',';', etc. are not allowed
  627. %
  628. %  - only variables and constants are allowed as arguments,
  629. %    i.e. no structured terms
  630. %
  631. %
  632. --------------------------------------------------------------------------------------
  633.  
  634. translate_projection(var(VarId),Dict,SelectList):-
  635.    projection_arguments([var(VarId)],SelectList,Dict).
  636.  
  637. translate_projection(const(Const),_,[const(Const)]).
  638.  
  639. translate_projection(ProjectionTerm,Dict,SelectList):-
  640.    ProjectionTerm =.. [Functor|Arguments],
  641.    not (Functor = var),
  642.    not (Functor = const),
  643.    not (Arguments = []),
  644.    projection_arguments(Arguments,SelectList,Dict).
  645.  
  646.  
  647.  
  648. projection_arguments([],[],_).
  649.  
  650. projection_arguments([Arg|RestArgs],[Att|RestAtts],Dict):-
  651.    retrieve_argument(Arg,Att,Dict),
  652.    projection_arguments(RestArgs,RestAtts,Dict).
  653.  
  654.  
  655.  
  656.  
  657. % - retrieve_argument(Argument,SQLAttribute,Dictionary)
  658. --------------------------------
  659. %
  660. % retrieves the mapping of an argument to the appropriate SQL construct,
  661. i.e.
  662. %
  663. %  - qualified attribute names for variables in base goals
  664. %  - arithmetic expressions for variables in arithmetic goals
  665. %  - constant values for constants
  666. %
  667. --------------------------------------------------------------------------------------
  668.  
  669. retrieve_argument(var(VarId),Attribute,Dict):-
  670.    lookup(VarId,Dict,TableName,AttName,_),
  671.    (
  672.     TableName = is ->
  673.       Attribute = AttName
  674.    ;
  675.       Attribute = att(TableName,AttName)
  676.    ).
  677.  
  678. retrieve_argument(const(Constant),const(Constant),_).
  679.  
  680.  
  681.  
  682.  
  683.  
  684. % --- lookup(Key,Dict,Value)
  685. -----------------------------------------------------------
  686.  
  687. lookup(VarId,Dict,RangeVar,Attribute,Type):-
  688.    member(dict(VarId,RangeVar,Attribute,Type,Quant),Dict),
  689.    (
  690.     Quant = all ->
  691.       true
  692.    ;
  693.       nonvar(RangeVar),
  694.       nonvar(Attribute)
  695.    ).
  696.  
  697.  
  698.  
  699. % --- add_to_dictionary(Key,RangeVar,Attribute,Quantifier,Dict,NewDict)
  700. ----------------
  701.  
  702. add_to_dictionary(Key,RangeVar,Attribute,Type,_,Dict,Dict):-
  703.    member(dict(Key,RangeVar,Attribute,Type,existential),Dict).
  704.  
  705. add_to_dictionary(Key,RangeVar,Attribute,Type,Quantifier,Dict,NewDict):-
  706.    not member(dict(Key,_,_,_,_),Dict),
  707.    NewDict = [dict(Key,RangeVar,Attribute,Type,Quantifier)|Dict].
  708.  
  709.  
  710.  
  711.  
  712. % --- aggregate_function(AggregateFunctionTerm,Dict,AggregateFunctionQuery)
  713. ------------
  714. %
  715. % aggregate_function discerns five Prolog aggregate function terms: count,
  716. avg, min,
  717. % max, and sum. Each such term is has two arguments: a variable indicating
  718. the attribute
  719. % over which the function is to be computed, and a goal argument which must
  720. contain in 
  721. % at least one argument position the variable:
  722. %
  723. %    e.g.  avg(Seats,plane(Type,Seats))
  724. %
  725. % These aggregate function terms correspond to the SQL built-in aggregate
  726. functions.
  727. % RESTRICTION: AggregateGoal may only be conjunction of (positive or
  728. negative) base 
  729. % goals
  730. %
  731. --------------------------------------------------------------------------------------
  732.  
  733. aggregate_function(AggregateFunctionTerm,Dict,AggregateFunctionExpression):-
  734.    AggregateFunctionTerm =..[AggFunctor,AggVar,AggGoal],
  735.    aggregate_functor(AggFunctor,SQLFunction),
  736.    conjunction(AggGoal,AggConjunction),
  737.   
  738. aggregate_query_generation(SQLFunction,AggVar,AggConjunction,Dict,AggregateFunctionExpression).
  739.  
  740.  
  741. conjunction(Goal,Conjunction):-
  742.    disjunction(Goal,[Conjunction]).
  743.  
  744.  
  745.  
  746.  
  747. % ---
  748. aggregate_query_generation(Function,FunctionVariable,AggGoal,Dict,AggregateQuery)
  749.  
  750. %
  751. % compiles the function variable (representing the attribute over which the
  752. aggregate 
  753. % function is to be computed) and the aggregate goal (representing the
  754. selection and 
  755. % join conditions for the computation of the aggregate function) to an SQL
  756. aggregate 
  757. % function subquery.
  758. %
  759. --------------------------------------------------------------------------------------
  760.  
  761. aggregate_query_generation(count,const('*'),AggGoal,Dict,AggregateQuery):-
  762.    translate_conjunction(AggGoal,SQLFrom,SQLWhere,Dict,TmpDict),
  763.  
  764.    % ATTENTION! It is assumed that in count(*) aggregate query terms there
  765. cannot be
  766.    % free variables because '*' stands for "all arguments"
  767.  
  768.    AggregateQuery =
  769. agg_query(Function,(count,[const(*)]),SQLFrom,SQLWhere,[]).
  770.  
  771.  
  772. aggregate_query_generation(Function,FunctionVariable,AggGoal,Dict,AggregateQuery):-
  773.    translate_conjunction(AggGoal,SQLFrom,SQLWhere,Dict,TmpDict),
  774.  
  775.    % --- only variables occurring in the aggregate goal are relevant to the
  776. translation
  777.    % of the function variable and the free variables in the goal.
  778.    % Thus subtract from TmpDict all entries of Dict
  779.    set_difference(TmpDict,Dict,AggDict),
  780.  
  781.    translate_projection(FunctionVariable,AggDict,SQLSelect),
  782.    translate_grouping(FunctionVariable,AggDict,SQLGroup),
  783.    AggregateQuery =
  784. agg_query(Function,SQLSelect,SQLFrom,SQLWhere,SQLGroup).
  785.  
  786.  
  787.  
  788.  
  789. % --- translate_grouping(FunctionVariable,Dict,SQLGroup)
  790. -------------------------------
  791. %
  792. % finds the free variables in the aggregate function term and collects
  793. their
  794. % corresponding SQL qualified attributes in the SQLGroup list.
  795. %
  796. --------------------------------------------------------------------------------------
  797.  
  798. translate_grouping(FunctionVariable,Dict,SQLGroup):-
  799.    free_vars(FunctionVariable,Dict,FreeVariables),
  800.    translate_free_vars(FreeVariables,SQLGroup).
  801.  
  802.  
  803.  
  804.  
  805. % --- free_vars(FunctionVariable,Dict,FreeVarList)
  806. -------------------------------------
  807. %
  808. % A Variable is free if it neither occurs as the FunctionVariable, nor is
  809. stored as
  810. % existentially quantified (through ^/2 in the original goal) in the
  811. dictionary
  812. % FreeVars contains for each variable the relevant attribute and relation
  813. information 
  814. % contained in the dictionary
  815. %
  816. --------------------------------------------------------------------------------------
  817.  
  818. free_vars(FunctionVariable,Dict,FreeVarList):-
  819.   projection_term_variables(FunctionVariable,FunctionVariableList),
  820.   findall((Var,Table,Attribute),
  821.       (member(dict(Var,Table,Attribute,all),Dict),
  822.        not member(dict(Var_,_,_),FunctionVariableList)
  823.       ),
  824.       FreeVarList).
  825.  
  826.  
  827. % --- function_variable_list(FunctionVariable,FunctionVariableList)
  828. --------------------
  829. %
  830. % extracts the list of variables which occur in the function variable term
  831. %
  832. % RESTRICTION: FunctionVariable may only contain one single variable.
  833. %
  834. --------------------------------------------------------------------------------------
  835.  
  836. function_variable_list(var(VarId),[VarId]).
  837.  
  838.  
  839.  
  840.  
  841. % --- translate_free_vars(FreeVars,SQLGroup)
  842. -------------------------------------------
  843. %
  844. % translates dictionary information on free variables to SQLGroup of
  845. aggregate
  846. % function query
  847. %
  848. --------------------------------------------------------------------------------------
  849.  
  850. translate_free_vars([],[]).
  851. translate_free_vars([(VarId,Table,Attribute)|FreeVars],[att(Table,Attribute)|SQLGroups]):-
  852.    translate_free_vars(FreeVars,SQLGroups).
  853.  
  854.  
  855.  
  856.  
  857. % --- evaluable_expression(ExpressionTerm,Dictionary,Expression,Type)
  858. --------------------
  859. %
  860. % evaluable_expression constructs SQL arithmetic expressions with qualified
  861. attribute names
  862. % from the Prolog arithmetic expression term and the information stored in
  863. the dictionary.
  864. %
  865. % The type of an evaluable function is returned in the argument Type.
  866. %
  867. % The dictionary is not changed because it is used for lookup only. 
  868.  
  869. evaluable_expression(AggregateFunctionTerm,Dictionary,AggregateFunctionExpression,number):-
  870.   
  871. aggregate_function(AggregateFunctionTerm,Dictionary,AggregateFunctionExpression).
  872.  
  873. evaluable_expression(LeftExp + RightExp,Dictionary,LeftAr +
  874. RightAr,number):-
  875.    evaluable_expression(LeftExp,Dictionary,LeftAr,number),
  876.    evaluable_expression(RightExp,Dictionary,RightAr,number).
  877.  
  878. evaluable_expression(LeftExp - RightExp,Dictionary,LeftAr -
  879. RightAr,number):-
  880.    evaluable_expression(LeftExp,Dictionary,LeftAr,number),
  881.    evaluable_expression(RightExp,Dictionary,RightAr,number).
  882.  
  883. evaluable_expression(LeftExp * RightExp,Dictionary,LeftAr *
  884. RightAr,number):-
  885.    evaluable_expression(LeftExp,Dictionary,LeftAr,number),
  886.    evaluable_expression(RightExp,Dictionary,RightAr,number).
  887.  
  888. evaluable_expression(LeftExp / RightExp,Dictionary, LeftAr /
  889. RightAr,number):-
  890.    evaluable_expression(LeftExp,Dictionary,LeftAr,number),
  891.    evaluable_expression(RightExp,Dictionary,RightAr,number).
  892.  
  893. evaluable_expression(var(VarId),Dictionary,att(RangeVar,Attribute),Type):-
  894.    lookup(VarId,Dictionary,RangeVar,Attribute,Type),
  895.    RangeVar \= is.
  896.  
  897. evaluable_expression(var(VarId),Dictionary,ArithmeticExpression,Type):-
  898.    lookup(VarId,Dictionary,is,ArithmeticExpression,Type).
  899.  
  900. evaluable_expression(const(Const),_,const(Const),ConstType):-
  901.    get_type(const(Const),ConstType).
  902.