home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #31 / NN_1992_31.iso / spool / comp / lang / prolog / 2292 < prev    next >
Encoding:
Internet Message Format  |  1992-12-22  |  16.4 KB

  1. Path: sparky!uunet!dtix!darwin.sura.net!jvnc.net!yale.edu!ira.uka.de!fauern!lrz-muenchen.de!mac_server.cis.uni-muenchen.de!user
  2. From: draxler@cis.uni-muenchen.de (Christoph Draxler)
  3. Newsgroups: comp.lang.prolog
  4. Subject: Prolog to SQL compiler v. 1.1 (part 2/2)
  5. Message-ID: <draxler-221292135550@mac_server.cis.uni-muenchen.de>
  6. Date: 22 Dec 92 12:50:31 GMT
  7. Sender: news@news.lrz-muenchen.de (Mr. News)
  8. Followup-To: comp.lang.prolog
  9. Organization: CIS - Centrum fuer Informations- und Sprachverarbeitung
  10. Lines: 687
  11.  
  12. % --- CODE for SQL compiler continued from part 1/2 ---------
  13.  
  14.  
  15. %
  16. --------------------------------------------------------------------------------------
  17. %
  18. % Output to screen predicates - rather crude at the moment
  19. %
  20. %
  21. --------------------------------------------------------------------------------------
  22.  
  23.  
  24. % --- printqueries(Code)
  25. ---------------------------------------------------------------
  26.  
  27. printqueries([Query]):-
  28.    nl,
  29.    print_query(Query),
  30.    write(';'),
  31.    nl,
  32.    nl.
  33.  
  34. printqueries([Query|Queries]):-
  35.    not (Queries = []),
  36.    nl,
  37.    print_query(Query),
  38.    nl,
  39.    write('UNION'),
  40.    nl,
  41.    printqueries(Queries).
  42.  
  43.  
  44.  
  45. % --- print_query(QueryCode)
  46. -----------------------------------------------------------
  47.  
  48. print_query(query([agg_query(Function,Select,From,Where,Group)],_,_)):-
  49.    % --- ugly rule here: aggregate function only in SELECT Part of query
  50. ----
  51.    !,
  52.    print_query(agg_query(Function,Select,From,Where,Group)).
  53.  
  54. print_query(query(Select,From,Where)):-
  55.    print_clause('SELECT',Select,','),
  56.    nl,
  57.    print_clause('FROM',From,','),
  58.    nl,
  59.    print_clause('WHERE',Where,'AND'),
  60.    nl.
  61.  
  62. print_query(agg_query(Function,Select,From,Where,Group)):-
  63.    print_clause('SELECT',Function,Select,','),
  64.    nl,
  65.    print_clause('FROM',From,','),
  66.    nl,
  67.    print_clause('WHERE',Where,'AND'),
  68.    nl,
  69.    print_clause('GROUP BY',Group,',').
  70.  
  71. print_query(negated_existential_subquery(Select,From,Where)):-
  72.    write('NOT EXISTS'),
  73.    nl,
  74.    write('('),
  75.    print_clause('SELECT',Select,','),
  76.    nl,
  77.    print_clause('FROM',From,','),
  78.    nl,
  79.    print_clause('WHERE',Where,'AND'),
  80.    nl,
  81.    write(')').
  82.  
  83.  
  84.  
  85.  
  86. % --- print_clause(Keyword,ClauseCode,Separator)
  87. ---------------------------------------
  88. %
  89. % with 
  90. % Keyword    one of SELECT, FROM, WHERE, or GROUP BY, 
  91. % ClauseCode the code corresponding to the appropriate clause of an SQL
  92. query, and 
  93. % Separator  indicating the character(s) through which the items of a
  94. clause
  95. %            are separated from each other (',' or 'AND').
  96. %
  97. --------------------------------------------------------------------------------------
  98.  
  99. print_clause(Keyword,[],_).
  100.  
  101. print_clause(Keyword,[Column|RestColumns],Separator):-
  102.    write(Keyword),
  103.    write(' '),
  104.    print_clause([Column|RestColumns],Separator).
  105.  
  106. print_clause(Keyword,Function,[Column],Separator):-
  107.    write(Keyword),
  108.    write(' '),
  109.    write(Function),
  110.    write('('),
  111.    print_clause([Column],Separator),
  112.    write(')').
  113.  
  114.  
  115.  
  116.  
  117.  
  118. % --- print_clause(ClauseCode,Separator)
  119. -----------------------------------------------
  120.  
  121. print_clause([Item],_):-
  122.    print_column(Item).
  123.  
  124. print_clause([Item,NextItem|RestItems],Separator):-
  125.    print_column(Item),
  126.    write(' '),
  127.    write(Separator),
  128.    write(' '),
  129.    print_clause([NextItem|RestItems],Separator).
  130.  
  131.  
  132.  
  133.  
  134. % --- print_column(ColumnCode) --------------------------------
  135.  
  136. print_column('*'):-
  137.    write('*').
  138.  
  139. print_column(att(RangeVar,Attribute)):-
  140.    write(RangeVar),
  141.    write('.'),
  142.    write(Attribute).
  143.  
  144. print_column(rel(Relation,RangeVar)):-
  145.    write(Relation),
  146.    write(' '),
  147.    write(RangeVar).
  148.  
  149. print_column(const(String)):-
  150.    get_type(const(String),string),
  151.    write('"'),
  152.    write(String),
  153.    write('"').
  154.  
  155. print_column(const(Number)):-
  156.    get_type(const(Number),NumType),
  157.    type_compatible(NumType,number),
  158.    write(Number).
  159.  
  160. print_column(comp(LeftArg,Operator,RightArg)):-
  161.    print_column(LeftArg),
  162.    write(' '),
  163.    write(Operator),
  164.    write(' '),
  165.    print_column(RightArg).
  166.  
  167. print_column(LeftExpr * RightExpr):-
  168.    print_column(LeftExpr),
  169.    write('*'),
  170.    print_column(RightExpr).
  171.  
  172. print_column(LeftExpr / RightExpr):-
  173.    print_column(LeftExpr),
  174.    write('/'),
  175.    print_column(RightExpr).
  176.  
  177. print_column(LeftExpr + RightExpr):-
  178.    print_column(LeftExpr),
  179.    write('+'),
  180.    print_column(RightExpr).
  181.  
  182. print_column(LeftExpr - RightExpr):-
  183.    print_column(LeftExpr),
  184.    write('-'),
  185.    print_column(RightExpr).
  186.  
  187. print_column(agg_query(Function,Select,From,Where,Group)):-
  188.    nl,
  189.    write('('),
  190.    print_query(agg_query(Function,Select,From,Where,Group)),
  191.    write(')').
  192.  
  193. print_column(negated_existential_subquery(Select,From,Where)):-
  194.    print_query(negated_existential_subquery(Select,From,Where)).
  195.  
  196.  
  197.  
  198.  
  199.  
  200. % --- queries_atom(Queries,QueryAtom) ---------------------------- 
  201. %
  202. % queries_atom(Queries,QueryAtom) returns in its second argument
  203. % the SQL query as a Prolog atom. For efficiency reasons, a list
  204. % of ASCII codes is ceated as a difference list, and it is then 
  205. % transformed to an atom by name/2
  206. % ---------------------------------------------------------------- 
  207.  
  208.  
  209. queries_atom(Queries,QueryAtom):-
  210.    queries_atom(Queries,QueryList,[]),
  211.    name(QueryAtom,QueryList).
  212.  
  213.  
  214.  
  215. queries_atom([Query],QueryList,Diff):-
  216.    query_atom(Query,QueryList,Diff).
  217.  
  218. queries_atom([Query|Queries],QueryList,Diff):-
  219.    Queries \= [],
  220.    query_atom(Query,QueryList,X1),
  221.    column_atom('UNION',X1,X2),
  222.    queries_atom(Queries,X2,Diff).
  223.  
  224.  
  225.  
  226. % --- query_atom(QueryCode) --------------------------------
  227.  
  228. query_atom(query([agg_query(Function,Select,From,Where,Group)],_,_),QueryList,Diff):-
  229.    % --- ugly rule here: aggregate function only in SELECT Part of query
  230. ----
  231.    !,
  232.    query_atom(agg_query(Function,Select,From,Where,Group),QueryList,Diff).
  233.  
  234. query_atom(query(Select,From,Where),QueryList,Diff):-
  235.    clause_atom('SELECT',Select,',',QueryList,X1),
  236.    clause_atom('FROM',From,',',X1,X2),
  237.    clause_atom('WHERE',Where,'AND',X2,Diff).
  238.  
  239. query_atom(agg_query(Function,Select,From,Where,Group),QueryList,Diff):-
  240.    clause_atom('SELECT',Select,',',QueryList,X1),
  241.    clause_atom('FROM',From,',',X1,X2),
  242.    clause_atom('WHERE',Where,'AND',X2,X3),
  243.    clause_atom('GROUP BY',Group,',',X3,Diff).
  244.  
  245. query_atom(negated_existential_subquery(Select,From,Where),QueryList,Diff):-
  246.    column_atom('NOT EXISTS(',QueryList,X1),   
  247.    clause_atom('SELECT',Select,',',X1,X2),
  248.    clause_atom('FROM',From,',',X2,X3),
  249.    clause_atom('WHERE',Where,'AND',X3,X4),
  250.    column_atom(')',X4,Diff).
  251.  
  252.  
  253.  
  254.  
  255. % --- clause_atom(Keyword,ClauseCode,Junctor,CurrAtom,QueryAtom)
  256. -------------
  257. %
  258. % with 
  259. % Keyword    one of SELECT, FROM, WHERE, or GROUP BY, 
  260. % ClauseCode the code corresponding to the appropriate clause of an SQL
  261. query, and 
  262. % Junctor    indicating the character(s) through which the items of a
  263. clause
  264. %            are separated from each other (',' or 'AND').
  265.  
  266. clause_atom(Keyword,[],_,QueryList,QueryList).
  267.  
  268. clause_atom(Keyword,[Column|RestColumns],Junctor,QueryList,Diff):-
  269.    column_atom(Keyword,QueryList,X1),
  270.    column_atom(' ',X1,X2),
  271.    clause_atom([Column|RestColumns],Junctor,X2,X3),
  272.    column_atom(' ',X3,Diff).
  273.  
  274. clause_atom(Keyword,Function,[Column],Junctor,QueryList,Diff):-
  275.    column_atom(Keyword,QueryList,X1),
  276.    column_atom('(',X1,X2),
  277.    clause_atom([Column],Junctor,X2,X3),
  278.    column_atom(')',X3,Diff).
  279.  
  280.  
  281.  
  282.  
  283.  
  284.  
  285. % --- clause_atom(ClauseCode,Junctor) --------------------------------
  286.  
  287. clause_atom([Item],_,QueryList,Diff):-
  288.    column_atom(Item,QueryList,Diff).
  289.  
  290. clause_atom([Item,NextItem|RestItems],Junctor,QueryList,Diff):-
  291.    column_atom(Item,QueryList,X1),
  292.    column_atom(' ',X1,X2),
  293.    column_atom(Junctor,X2,X3),
  294.    column_atom(' ',X3,X4),
  295.    clause_atom([NextItem|RestItems],Junctor,X4,Diff).
  296.  
  297.  
  298.  
  299.  
  300.  
  301. column_atom(att(RangeVar,Attribute),QueryList,Diff):-
  302.    column_atom(RangeVar,QueryList,X1),
  303.    column_atom('.',X1,X2),
  304.    column_atom(Attribute,X2,Diff).
  305.  
  306. column_atom(rel(Relation,RangeVar),QueryList,Diff):-
  307.    column_atom(Relation,QueryList,X1),
  308.    column_atom(' ',X1,X2),
  309.    column_atom(RangeVar,X2,Diff).
  310.  
  311. column_atom(const(String),QueryList,Diff):-
  312.    get_type(const(String),string),
  313.    column_atom('"',QueryList,X1),
  314.    column_atom(String,X1,X2),
  315.    column_atom('"',X2,Diff).
  316.  
  317. column_atom(const(Number),QueryList,Diff):-
  318.    get_type(const(Number),NumType),
  319.    type_compatible(NumType,number),
  320.    column_atom(Number,QueryList,Diff).
  321.  
  322. column_atom(comp(LeftArg,Operator,RightArg),QueryList,Diff):-
  323.    column_atom(LeftArg,QueryList,X1),
  324.    column_atom(' ',X1,X2),
  325.    column_atom(Operator,X2,X3),
  326.    column_atom(' ',X3,X4),
  327.    column_atom(RightArg,X4,Diff).
  328.  
  329. column_atom(LeftExpr * RightExpr,QueryList,Diff):-
  330.    column_atom(LeftExpr,QueryList,X1),
  331.    column_atom('*',X1,X2),
  332.    column_atom(RightExpr,X2,Diff).
  333.  
  334. column_atom(LeftExpr + RightExpr,QueryList,Diff):-
  335.    column_atom(LeftExpr,QueryList,X1),
  336.    column_atom('+',X1,X2),
  337.    column_atom(RightExpr,X2,Diff).
  338.  
  339. column_atom(LeftExpr - RightExpr,QueryList,Diff):-
  340.    column_atom(LeftExpr,QueryList,X1),
  341.    column_atom('-',X1,X2),
  342.    column_atom(RightExpr,X2,Diff).
  343.  
  344. column_atom(LeftExpr / RightExpr,QueryList,Diff):-
  345.    column_atom(LeftExpr,QueryList,X1),
  346.    column_atom('/',X1,X2),
  347.    column_atom(RightExpr,X2,Diff).
  348.  
  349. column_atom(agg_query(Function,Select,From,Where,Group),QueryList,Diff):-
  350.    column_atom('(',QueryList,X1),
  351.    query_atom(agg_query(Function,Select,From,Where,Group),X1,X2),
  352.    column_atom(')',X2,Diff).
  353.  
  354. column_atom(negated_existential_subquery(Select,From,Where),QueryList,Diff):-
  355.   
  356. query_atom(negated_existential_subquery(Select,From,Where),QueryList,Diff).
  357.  
  358.  
  359. column_atom(Atom,List,Diff):-
  360.    atom(Atom),
  361.    name(Atom,X1),
  362.    append(X1,Diff,List).
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369. % --- benchmarks of sample queries
  370. --------------------------------------------
  371. %
  372. % benchmark(N,No,Duration) runs the query No N times and returns the
  373. runtime
  374. %
  375. % To run each benchmark once, enter ?- benchmark(1,No,D). and type ; after
  376. % a solution has been returned.
  377. %
  378. %
  379. -----------------------------------------------------------------------------
  380.  
  381. benchmark(N,1,D):-
  382.    cpu_time(N,
  383.      (translate(flight(No,Dep,Dest,Type),flight(No,Dep,Dest,Type),Code),
  384.       printqueries(Code)),
  385.    D).
  386.  
  387. benchmark(N,2,D):-
  388.    cpu_time(N,
  389.      (translate(capacity(No,Dep,Dest,Type,Seats),
  390.         (flight(No,Dep,Dest,Type),
  391.          plane(Type,Seats),
  392.          Type='b-737'),Code),
  393.        printqueries(Code)),
  394.    D).
  395.  
  396. benchmark(N,3,D):-
  397.    cpu_time(N,
  398.       (translate(no_planes(No,Dep,Dest,Type),
  399.           (flight(No,Dep,Dest,Type),
  400.            not plane(Type,Seats)),Code),
  401.        printqueries(Code)),
  402.     D).
  403.  
  404. benchmark(N,4,D):-
  405.    cpu_time(N,(translate(X,X is
  406. count(S,plane(P,S)),Code),printqueries(Code)),D).
  407.  
  408. benchmark(N,5,D):-
  409.    cpu_time(N,
  410.       (translate(big_planes(munich,Dest,Type,Seats),
  411.           FNo^(flight(FNo,munich,Dest,Type),
  412.                plane(Type,Seats),
  413.                Seats > avg(S, T^plane(T,S))),Code),
  414.       printqueries(Code)),
  415.    D).
  416.  
  417. benchmark(N,6,D):-
  418.    cpu_time(N,(
  419.      translate(big_planes(munich,Dest,Type,Seats),
  420.          FNo^(flight(FNo,munich,Dest,Type),
  421.               plane(Type,Seats),
  422.               Seats > avg(S, T^plane(T,S))),Code),
  423.          printqueries(Code)),
  424.    D).
  425.  
  426. benchmark(N,7,D):-
  427.    cpu_time(N,(
  428.      translate(big_planes(munich,Dest,Type,Seats),
  429.          FNo^(flight(FNo,munich,Dest,Type),
  430.               plane(Type,Seats),
  431.               Seats > avg(S, T^plane(T,S))),Code),
  432.          queries_atom(Code,SQLQueryAtom),
  433.          writeq(query_atom(SQLQueryAtom)),
  434.          nl),
  435.    D).
  436.  
  437.  
  438.  
  439.  
  440. % --- gensym(Root,Symbol)
  441. ----------------------------------------------------
  442. %
  443. % SEPIA 3.0.7. version - other Prolog implementations provide gensym/2
  444. % and init_gensym/1 as built-ins. */
  445. %
  446. % (C) Christoph Draxler, Aug. 1992
  447. %
  448.  
  449. gensym(Root,Symbol):-
  450.    not var(Root),
  451.    var(Symbol),
  452.  
  453.    incval(Root),
  454.    getval(Root,Counter),
  455.  
  456.    % --- create char list of root and counter ---
  457.    name(Root,RootList),
  458.    name(Counter,CounterList),
  459.  
  460.    % --- append RootList and CounterList ---
  461.    append(RootList,CounterList,SymbolList),
  462.  
  463.    % --- create atom from SymbolList ---
  464.    name(Symbol,SymbolList).
  465.  
  466.  
  467. init_gensym(Root):-
  468.    not var(Root),
  469.    setval(Root,0).
  470.  
  471.  
  472.  
  473. % --- auxiliary predicates
  474. -----------------------------------------------------
  475. %
  476. % Some Prologs have Bem, some donBt. 
  477. %
  478. %
  479. ------------------------------------------------------------------------------
  480.  
  481. append([],L,L).
  482. append([H1|L1],L2,[H1|L3]):-
  483.    append(L1,L2,L3).
  484.  
  485.  
  486.  
  487. member(X,[X|_]).
  488. member(X,[_|T]):-
  489.    member(X,T).
  490.  
  491.  
  492.  
  493. repeat_n(N):-
  494.    integer(N),
  495.    N > 0,
  496.    repeat_1(N).
  497.  
  498. repeat_1(1):-!.
  499. repeat_1(_).
  500. repeat_1(N):-
  501.    N1 is N-1,
  502.    repeat_1(N1).
  503.  
  504.  
  505.  
  506. % --- benchmark programs for translation of database goals ---------------
  507. %
  508. % taken from R. O'Keefe: The Craft of Prolog, MIT Press 1990
  509. %
  510. % Sepia Prolog version
  511.  
  512. cpu_time(Time):-
  513.    cputime(Time).
  514.  
  515.  
  516. cpu_time(Goal,Duration):-
  517.    !,
  518.    cputime(T1),
  519.    (call(Goal) -> true; true),
  520.    cputime(T2),
  521.    Duration is T2 - T1.
  522.  
  523. cpu_time(N,Goal,Duration):-
  524.    !,
  525.    cpu_time((repeat_n(N),(Goal -> fail);true),D1),
  526.    cpu_time((repeat_n(N),(true -> fail);true),D2),
  527.    Duration is D1 - D2.
  528.  
  529.  
  530.  
  531. % --- set_difference(SetA,SetB,Difference)
  532. --------------------------------------------
  533. %
  534. % SetA - SetB = Difference
  535.  
  536. set_difference([],_,[]).
  537.  
  538. set_difference([Element|RestSet],Set,[Element|RestDifference]):-
  539.    not member(Element,Set),
  540.    set_difference(RestSet,Set,RestDifference).
  541.  
  542. set_difference([Element|RestSet],Set,RestDifference):-
  543.    member(Element,Set),
  544.    set_difference(RestSet,Set,RestDifference).
  545.  
  546.  
  547.  
  548.  
  549. % --- Meta Database for schema definition of SQL DB in Prolog
  550. --------------------------
  551. %
  552. % maps Prolog predicates to SQL table names, Prolog predicate argument
  553. positions to SQL
  554. % attributes, and Prolog operators to SQL operators. 
  555. %
  556. % ATTENTION! It is assumed that the arithmetic operators in Prolog and SQL
  557. are the same,
  558. % i.e. + is addition in Prolog and in SQL, etc. If this is not the case,
  559. then a mapping
  560. % function for arithmetic operators is necessary too.
  561. %
  562. % CHANGE THIS TO MEET YOUR DATABASE SCHEMA!
  563. %
  564. %
  565. --------------------------------------------------------------------------------------
  566.  
  567.  
  568. % --- relation(PrologFunctor,Arity,SQLTableName)
  569. ---------------------------------------
  570.  
  571. relation(flight,4,'FLIGHT').
  572. relation(plane,2,'PLANE').
  573.  
  574.  
  575. % --- attribute(PrologArgumentPosition,SQLTableName,SQLAttributeName)
  576. ------------------
  577.  
  578. attribute(1,'FLIGHT','FLIGHT_NO',string).
  579. attribute(2,'FLIGHT','DEPARTURE',string).
  580. attribute(3,'FLIGHT','DESTINATION',string).
  581. attribute(4,'FLIGHT','PLANE_TYPE',string).
  582.  
  583.  
  584. attribute(1,'PLANE','TYPE',string).
  585. attribute(2,'PLANE','SEATS',integer).
  586.  
  587.  
  588. % --- Mapping of Prolog operators to SQL operators
  589. -------------------------------------
  590.  
  591. comparison(=,=).
  592. comparison(<,<).
  593. comparison(>,>).
  594. comparison(@<,<).
  595. comparison(@>,>).
  596.  
  597.  
  598. negated_comparison(=,'<>').
  599. negated_comparison(\=,=).
  600. negated_comparison(>,=<).
  601. negated_comparison(=<,>).
  602. negated_comparison(<,>=).
  603. negated_comparison(>=,<).
  604.  
  605.  
  606. % --- aggregate_function(PrologFunctor,SQLFunction) -----------------
  607.  
  608. aggregate_functor(avg,'AVG').
  609. aggregate_functor(min,'MIN').
  610. aggregate_functor(max,'MAX').
  611. aggregate_functor(sum,'SUM').
  612. aggregate_functor(count,'COUNT').
  613.  
  614.  
  615.  
  616. % --- type system
  617. --------------------------------------------------------------
  618. %
  619. % A rudimentary type system is provided for consistency checking during the
  620. % translation and for output formatting
  621. %
  622. % The basic types are string and number. number has the subtypes integer
  623. and
  624. % real.
  625. %
  626. %
  627. ------------------------------------------------------------------------------
  628.  
  629.  
  630. type_compatible(Type,Type):-
  631.    is_type(Type).
  632. type_compatible(SubType,Type):-
  633.    subtype(SubType,Type).
  634. type_compatible(Type,SubType):-
  635.    subtype(SubType,Type).
  636.  
  637.  
  638. % --- subtype(SubType,SuperType)
  639. -----------------------------------------------
  640. %
  641. % Simple type hierarchy checking
  642. %
  643. %
  644. ------------------------------------------------------------------------------
  645.  
  646. subtype(SubType,SuperType):-
  647.    is_subtype(SubType,SuperType).
  648.  
  649. subtype(SubType,SuperType):-
  650.    is_subtype(SubType,InterType),
  651.    subtype(InterType,SuperType).
  652.  
  653.  
  654.  
  655. % --- is_type(Type)
  656. ------------------------------------------------------------
  657. %
  658. % Type names
  659. %
  660. %
  661. ------------------------------------------------------------------------------
  662.  
  663. is_type(number).
  664. is_type(integer).
  665. is_type(real).
  666. is_type(string).
  667. is_type(natural).
  668.  
  669.  
  670. % --- is_subtype(SubType,SuperType)
  671. --------------------------------------------
  672. %
  673. % Simple type hierarchy for numeric types
  674. %
  675. %
  676. ------------------------------------------------------------------------------
  677.  
  678. is_subtype(integer,number).
  679. is_subtype(real,number).
  680. is_subtype(natural,integer).
  681.  
  682.  
  683. % --- get_type(Constant,Type)
  684. --------------------------------------------------
  685. %
  686. % Prolog implementation specific definition of type retrieval
  687. % sepia Prolog version given here
  688. %
  689. %
  690. ------------------------------------------------------------------------------
  691.  
  692. get_type(const(Constant),integer):-
  693.    number(Constant).
  694.  
  695. get_type(const(Constant),string):-
  696.    atom(Constant).
  697.