1/* Part of SWISH 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@cs.vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (C): 2017, VU University Amsterdam 7 CWI Amsterdam 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- module(swish_projection, 37 [ projection/1 38 ]). 39:- use_module(library(lists)). 40:- use_module(library(apply)). 41:- use_module(library(debug)). 42:- use_module(library(error)). 43 44/** <module> Define the projection 45 46This module redefines variables that are included in the SWISH result 47set. 48 49@tbd Removed variables should be removed from the template as well 50 for efficiency reasons. 51*/ 52 53:- multifile 54 reserved_var/1. % +VarName 55 56%! projection(+Spec:list) 57% 58% Specify the result variables. Using projection/1 at the start of a 59% query specifies which variables are part of the result set, in what 60% order they are displayed and, optionally, whether the results must 61% be ordered on one or more variables or the solutions should be 62% distinct. Each element of Spec is one of the following: 63% 64% - Var 65% Include Var in the result. Var must appear in the remainder of 66% the body. 67% - Var:Annotation 68% As Var, respecting Annotation. Valid annotations are below. 69% Annotations may be abbreviated, e.g. `asc`, `desc` 70% 71% - ascending 72% Order solutions in ascending order. 73% - descending 74% Order solutions is descending order 75% - distinct 76% Remove duplicates wrt. this argument. 77% - AnnA+AnnB 78% Multiple annotations 79% 80% - +Var 81% Equivalent to `Var:ascending` 82% - -Var 83% Equivalent to `Var:descending` 84% 85% If ordering is specified for multiple variables, the result set is 86% ordered starting with the left-most variable for which ordering is 87% defined. 88 89projection(_). 90 91swishgoal_expansion((Projection,Body), Aggregate) :- 92 nonvar(Projection), 93 Projection = projection(Spec), 94 must_be(list, Spec), 95 aggregation(Spec, Vars, Body, Aggregate), 96 !, 97 ignore(set_projection(Vars)). 98swishgoal_expansion(projection(Vars), true) :- 99 set_projection(Vars). 100 101set_projection(Vars) :- 102 nb_current('$variable_names', Bindings), 103 debug(projection, 'Got ~p; Asking ~p', [Bindings, Vars]), 104 preverse_vars(Bindings, NewVars, SelectedBindings), 105 maplist(select_binding(Bindings), Vars, SelectedBindings), 106 debug(projection, 'Filtered ~p', [NewVars]), 107 b_setval('$variable_names', NewVars). 108 109%! preverse_vars(+Bindings, -ReservedBindings, ?Tail) is det. 110% 111% Preserve some of the _pseudo bindings_ that communicate additional 112% information from the Pengine. May be extended by adding clauses to 113% reserved_var/1. 114 115preverse_vars([], L, L). 116preverse_vars([Name=Var|T0], [Name=Var|T], L) :- 117 reserved_var(Name), 118 !, 119 preverse_vars(T0, T, L). 120preverse_vars([_|T0], T, L) :- 121 preverse_vars(T0, T, L). 122 123reserved_var('_residuals'). 124reserved_var('_swish__permahash'). 125 126select_binding(Bindings, Var, Name=Var) :- 127 member(Name=X, Bindings), 128 Var == X, 129 !. 130 131%! aggregation(+Projection:list, -Vars, +Goal0, -Goal) is semidet. 132% 133% Determine the final projection variables as well as ordering and 134% distinct wrapper from the projection argument. 135 136aggregation(Projection, Vars, Goal0, Goal) :- 137 modifiers(Projection, Vars, Unique, Order), 138 munique(Unique, Goal0, Goal1), 139 morder(Order, Goal1, Goal). 140 141munique([], Goal, Goal) :- 142 !. 143munique(Vars, Goal0, distinct(Term, Goal0)) :- 144 Term =.. [v|Vars]. 145 146morder([], Goal, Goal) :- 147 !. 148morder(Vars, Goal0, order_by(Vars, Goal0)). 149 150modifiers(Projection, Vars, Unique, Order) :- 151 phrase(annotations(Projection, Vars), Annot), 152 Annot \== [], 153 partition(unique_anot, Annot, Unique, Order). 154 155unique_anot(distinct(_)). 156 157annotations([], []) --> 158 []. 159annotations([H|T], [V|VT]) --> 160 annotations1(H, V), 161 annotations(T, VT). 162 163annotations1(V, V) --> {var(V)}, !. 164annotations1(+V, V) --> !, [asc(V)]. 165annotations1(-V, V) --> !, [desc(V)]. 166annotations1(V:Ann, V) --> !, var_annotations(Ann, V). 167annotations1(V, V) --> []. 168 169var_annotations(Var, _) --> {var(Var), instantiation_error(Var)}. 170var_annotations(A+B, V) --> !, var_annotations(A,V), var_annotations(B,V). 171var_annotations(Anot, V) --> 172 { var_annotation(Anot, Can), 173 Term =.. [Can,V] 174 }, 175 [ Term ]. 176 177var_annotation(Anot, Cann) :- 178 var_anot1(Anot, Cann), 179 !, 180 ( var_anot1(Anot, Cann2), 181 Cann \== Cann2 182 -> domain_error(projection_annotation, Anot) 183 ; true 184 ). 185var_annotation(Anot, _Cann) :- 186 domain_error(projection_annotation, Anot). 187 188var_anot1(Anot, Cann) :- 189 var_annot(Long, Cann), 190 sub_atom(Long, 0, _, _, Anot). 191 192var_annot(ascending, asc). 193var_annot(descending, desc). 194var_annot(distinct, distinct). 195 196:- multifile sandbox:safe_primitive/1. 197 198sandbox:safe_primitive(swish_projection:projection(_))