34
42
43:-module(sql_parser, [sql_gripe_level/1,
44 sql_parse/4,
45 strip_sql_comments/2]).
124:-op(95, fx, @). 125:-op(100, fx, #). 127:-op(0, xfx, as). 128:-op(0, xfx, on). 129:-op(0, xfx, or). 130:-op(0, xfx, and). 131:-op(0, xfx, not). 132:-op(0, xfx, in). 133:-op(0, xfx, like). 134:-op(100, fx, ??). 135:-op(1200, xfx, --->). 136
137:-use_module(library(chr)). 138:-use_module(library(quintus), [otherwise/0]). 139:-use_module(library(dcg/basics)). 140:-use_module(library(cql/sql_keywords)). 141:-use_module(library(cql/sql_write)). 142:-use_module(library(cql/sql_tokenizer)). 143
144:-use_module(library(cql/cql), [default_schema/1,
145 cql_normalize_name/3,
146 dbms/2,
147 database_attribute/8,
148 domain_database_data_type/2,
149 routine_return_type/3,
150 sql_gripe/3]). 151
152:-chr_option(line_numbers, on). 153:-chr_option(check_guard_bindings, error). 154:-chr_option(debug, off). 155:-chr_option(optimize, full). 156:-chr_option(guard_simplification, off). 157
158:-chr_type 'Table' == any. 159:-chr_type 'Alias' == any. 160:-chr_type 'Type' == any. 161:-chr_type 'Column' == any. 162:-chr_type 'Constraint' == any. 163:-chr_type 'Vars' == any. 164:-chr_type 'N' == any. 165:-chr_type 'QueryId' == any. 166:-chr_type 'Source' == any. 167
168:-chr_constraint type_constraint(-'QueryId', ?'Source', ?'Type', ?'Constraint'). 169:-chr_constraint type_constraint_ready(-'QueryId', ?'Type'). 170:-chr_constraint type_merge_hint(?'Type', ?'Constraint'). 171:-chr_constraint query_table(-'QueryId', ?'Alias', ?'Table'). 172:-chr_constraint derived_query_column(-'QueryId', ?'Alias', ?'Column', ?'Type'). 173:-chr_constraint subquery(-'QueryId', -'QueryId'). 174:-chr_constraint peer_query(-'QueryId', -'QueryId'). 175:-chr_constraint query_is_xml(-'QueryId'). 176:-chr_constraint resolve_types(-'QueryId'). 177:-chr_constraint commit(-'QueryId'). 178:-chr_constraint union_type(-'QueryId', ?'Constraint', ?'Constraint', ?'Constraint'). 179:-chr_constraint derived_table(-'QueryId', +'Table', ?'Constraint'). 180:-chr_constraint find_all_column_types(-'QueryId', ?'Source', ?'Type'). 181:-chr_constraint force_type_not_domain(?'Type'). 182:-chr_constraint frozen_reverse(-'QueryId', ?'Constraint', ?'Constraint'). 183:-chr_constraint cleanup(-'QueryId'). 184
185:-dynamic(cached_gripe_level/1). 186sql_gripe_level(N):-
187 cached_gripe_level(N), !.
188sql_gripe_level(N):-
189 ( getenv('SQL_GRIPE_LEVEL', Atom),
190 atom_number(Atom, N)->
191 true
192 ; otherwise->
193 N = 0 194 ),
195 assert(cached_gripe_level(N)).
196
197
198stream_to_tokens(Stream, Tokens):-
199 stream_to_lazy_list(Stream, List),
200 sql_tokens(Tokens, List, []), !.
201
202
203sql_parse(Head, TrailingComments, Options, Tokens):-
204 Head =.. [Functor, Arg, Types|Args],
205 reverse(Tokens, TR),
206 trailing_comments_reversed(TR, TrailingCommentsReversed, Tail),
207 reverse(Tail, TokensWithoutTrailingComments),
208 reverse(TrailingCommentsReversed, TrailingComments),
209 Goal =.. [Functor, TokensWithoutTrailingComments, [], [query_id(QueryId)|Options], _, 0, _, Arg, T1 |Args],
210 Goal,
211 !,
212 213 214 resolve_types(QueryId),
215 map_nulls_to_ints(T1, Types),
216 consolidate_errors(Arg),
217 cleanup(QueryId),
218 true.
219
220
221map_nulls_to_ints([], []):- !.
222map_nulls_to_ints([merged(A, _, N)|As], [A-native_type(int)|Bs]):-
223 N == {nulltype}, !,
224 map_nulls_to_ints(As, Bs).
225map_nulls_to_ints([merged(A, _, N)|As], [A-native_type(int)|Bs]):-
226 nonvar(N), N = native_type(int(_)), !,
227 map_nulls_to_ints(As, Bs).
228map_nulls_to_ints([merged(A, _, AT)|As], [A-AT|Bs]):-
229 map_nulls_to_ints(As, Bs).
230
([], [], []):- !.
232trailing_comments_reversed([comment(A,B)|In], [comment(A,B)|More], Tail):- !,
233 trailing_comments_reversed(In, More, Tail).
234trailing_comments_reversed(Tail, [], Tail):- !.
235
236term_expansion(OldHead ---> OldBody, NewHead :- NewBody):-
237 OldHead =.. [Functor, A1|Args],
238 NewHead =.. [Functor, In, Out, ContextIn, _, P0, P1, meta(Comments, Source):A1|Args],
239 transform_body(OldBody, In, Out, Source, ContextIn, _, Comments, [], P0, P1, NewBody).
240
241transform_body({A}, In, Out, _, C, C, C1, C2, P0, P0, (A, Out = In, C1 = C2)):- !.
242transform_body(\+(X), In, In, Source, C, C, C1, C1, P0, P0, \+G):-
243 transform_body(X, In, _, Source, C, _, C1, _, P0, _, G).
244transform_body(??(X), In, Out, Source, CIn, COut, C1, C2, P0, P1, Transformed):-
245 transform_body(X, In, Out, Source, CIn, COut, C1, C2, P0, P1, G),
246 functor(X, Functor, Arity),
247 Transformed = (( length(First, 20), append(First, _, In)-> true ; otherwise-> First = In),
248 format(user_error, '----- CALL ~w (~q) ~w~n', [Functor/Arity, G, First]),
249 setup_call_catcher_cleanup(true,
250 G,
251 Reason,
252 ( Reason == ! ->
253 ( length(Last, 20), append(Last, _, Out)-> true ; otherwise-> Last = Out),
254 format(user_error, '----- CUT ~w ~w~n', [Functor/Arity, Last])
255 ; Reason == fail->
256 format(user_error, '----- FAIL ~w~n', [Functor/Arity])
257 ; Reason == exit->
258 ( length(Last, 20), append(Last, _, Out)-> true ; otherwise-> Last = Out),
259 format(user_error, '----- EXIT ~w ~w~n', [Functor/Arity, Last])
260 )),
261 ( var(Reason) ->
262 ( length(Last, 20), append(Last, _, Out)-> true ; otherwise-> Last = Out),
263 format(user_error, '----- PEND ~w ~w~n', [Functor/Arity, Last])
264 ; otherwise->
265 true
266 )
267 ).
268
269transform_body(get_source(Source), In, In, Source, C, C, C1, C1, P0, P0, true):- !.
270transform_body(get_parameter(P0), In, In, _, C, C, C1, C1, P0, P1, P1 is P0 + 1):- !.
271transform_body(!, InOut, InOut, _, C, C, C1, C2, P0, P0, (!, C1 = C2)):- !.
272transform_body(@Functor, In, Out, Source, C, C, C1, C2, P0, P0, get_token(Token, C, C1, C2, In, Out)):- Functor =.. [Token, Source], !.
273transform_body(@Token, In, Out, _, C, C, C1, C2, P0, P0, get_token(Token, C, C1, C2, In, Out)):- !.
274transform_body(#Identifier : Type, In, Out, _, C, C, C1, C2, P0, P0, get_identifier(Identifier, Type, C, C1, C2, In, Out)):-!.
275transform_body(#Identifier, In, Out, _, C, C, C1, C2, P0, P0, get_identifier(Identifier, any, C, C1, C2, In, Out)):-!.
276
277transform_body((A | B), In, Out, Source, CIn, COut, C1, C2, P0, P1, (C, COut = COut1, P1 = P1a ; D, COut = COut2, P1 = P1b)):-
278 !,
279 transform_body(A, In, Out, Source, CIn, COut1, C1, C2, P0, P1a, C),
280 transform_body(B, In, Out, Source, CIn, COut2, C1, C2, P0, P1b, D).
281transform_body((A,B), In, Out, Source, CIn, COut, C1, C2, P0, P2, (C,D)):-
282 !,
283 transform_body(A, In, Intermediate, Source, CIn, CInt, C1, C1b, P0, P1, C),
284 transform_body(B, Intermediate, Out, Source, CInt, COut, C1b, C2, P1, P2, D).
285
286transform_body(List, In, Out, Source, CIn, COut, C1, C2, P0, P1Out, (Goals, P1Out = P1 ; In = Out, CIn = COut, C1 = C2, P1Out = P0)):-
287 is_list(List), !,
288 transform_list_body(List, In, Out, Source, CIn, COut, C1, C2, P0, P1, Goals).
289transform_body(Rule, In, Out, _, CIn, CX, C1, C2, P0, P1, ( C1 = C2, NewRule )):-
290 Rule =.. [Functor|Args],
291 NewRule =.. [Functor, In, Out, CIn, COut, P0, P1|Args],
292 ( ( Functor == set_qid ; Functor == add_option)->
293 CX = COut
294 ; otherwise->
295 CX = CIn
296 ).
297transform_list_body([Tail], In, Out, Source, CIn, COut, C1, C2, P0, P1, Goals):-
298 transform_body(Tail, In, Out, Source, CIn, COut, C1, C2, P0, P1, Goals).
299transform_list_body([Head|Tail], In, Out, Source, CIn, COut, C1, C2, P0, P2, (G, G2)):-
300 transform_body(Head, In, Intermediate, Source, CIn, CInt, C1, C1b, P0, P1, G),
301 transform_list_body(Tail, Intermediate, Out, Source, CInt, COut, C1b, C2, P1, P2, G2).
302
303get_token(Token, Options, [comment(A,B)|C1], C2, [comment(A,B)|X], Out):- !,
304 get_token(Token, Options, C1, C2, X, Out).
305get_token(Token, Options, C1, C1, [TopToken|Out], Out):-
306 ( reverse_lex(TopToken, Options, Token)->
307 true
308 ; atom(TopToken),
309 downcase_atom(TopToken, Token)->
310 true
311 ).
312
313get_identifier(Identifier, Type, Options, [comment(A,B)|C1], C2, [comment(A,B)|X], Out):- !,
314 get_identifier(Identifier, Type, Options, C1, C2, X, Out).
315get_identifier(Identifier, Type, Options, C1, C1, [Top|Out], Out):-
316 ( Type == any ->
317 Identifier = Top
318 ; otherwise->
319 Top = literal(Identifier, Type)
320 ),
321 ( atom(Identifier)->
322 downcase_atom(Identifier, IdentifierLC),
323 \+reserved_sql_keyword(IdentifierLC)
324 ; otherwise->
325 true
326 ),
327 \+reverse_lex(Identifier, Options, _).
328
329reverse_lex('*', _Options, asterisk).
330reverse_lex('/', _Options, solidus).
331reverse_lex('+', _Options, plus_sign).
332reverse_lex('-', _Options, minus_sign).
333reverse_lex(',', _Options, comma).
334reverse_lex('.', _Options, period).
335reverse_lex('(', _Options, left_paren).
336reverse_lex(')', _Options, right_paren).
337reverse_lex('{', _Options, left_curly).
338reverse_lex('}', _Options, right_curly).
339reverse_lex('IS', _Options, is_keyword).
340reverse_lex('Is', _Options, is_keyword).
341reverse_lex('iS', _Options, is_keyword).
342reverse_lex('is', _Options, is_keyword).
343reverse_lex('<', _Options, less_than_operator).
344reverse_lex('=', _Options, equals_operator).
345reverse_lex('<>', _Options, not_equals_operator).
346reverse_lex('>', _Options, greater_than_operator).
347reverse_lex('<=', _Options, less_than_or_equals_operator).
348reverse_lex('>=', _Options, greater_than_or_equals_operator).
349reverse_lex('+', Options, concatenation_operator):- dbms([], [], Options, _, _, _, 'Microsoft SQL Server').
350reverse_lex('||', Options, concatenation_operator):- \+dbms([], [], Options, _, _, _, 'Microsoft SQL Server').
351
352
353add_option(L, L, O, [X|O], P, P, X).
354set_qid(L, L, O, O2, P, P, X):-
355 change_qid(O, X, O2).
356
357change_qid([query_id(_)|T], Qid, [query_id(Qid)|T]):- !.
358change_qid([A|T], Qid, [A|T2]):- !, change_qid(T, Qid, T2).
359
360get_option(L, L, O, O, P, P, X):- memberchk(X, O).
361qid(L, L, O, O, P, P, Qid):- memberchk(query_id(Qid), O).
362default_precision_and_scale(L, L, O, O, P0, P0, P, S):-
363 ( dbms(L, L, O, O, P0, P0, 'Microsoft SQL Server')->
364 P = 18,
365 S = 0
366 ; otherwise->
367 throw(default_unknown)
368 ).
369dbms(L, L, Options, Options, P, P, DBMS):-
370 ( memberchk(dbms(X), Options)->
371 DBMS = X
372 ; otherwise->
373 DBMS = 'Microsoft SQL Server'
374 ).
375
376check_order_by_is_in_top_query(L, L, Options, Options, P, P, Source):-
377 ( memberchk(subquery, Options)->
378 true
379 ; \+memberchk(view_name(_), Options)->
380 381 true
382 ; otherwise->
383 semantic_error(Source, order_by(top_level), 1)
384 ).
385
386action(Action, Types)--->
387 query_expression(Action, Types) | delete_statement_searched(Action, Types) | insert_statement(Action, Types) | update_statement_searched(Action, Types).
388delete_statement_searched(delete(TableName, Where), [])--->
389 @delete, @from, !, table_name(TableName), (@where, search_condition(Condition), {Where = where(Condition)} | {Where = {no_where}}).
390insert_statement(insert(TableName, Values), [])--->
391 @insert, @into, !, table_name(TableName), insert_columns_and_source(Values), [dbms('PostgreSQL'), @returning, query_expression(_,_)].
392insert_columns_and_source(Values)--->
393 from_subquery(Values) | from_constructor(Values) | from_default(Values).
394from_default({default_values})---> @default, @values, !.
395from_subquery(insert_source(Source, Override, Target))--->
396 ( ( @left_paren, insert_column_list(Source), @right_paren) | {Source = {default}} ),
397 ( override_clause(Override) | {Override = {no_override}} ),
398 query_expression(Target, _).
399from_constructor(insert_source(Source, Override, Target))--->
400 ( ( @left_paren, insert_column_list(Source), @right_paren) | {Source = {default}} ),
401 ( override_clause(Override) | {Override = {no_override}} ),
402 table_value_constructor(Target, _).
403update_statement_searched(update(TableName, List, From, Condition), [])--->
404 405 @update, table_reference(TableName),
406 qid(Qid), {strip_sql_comments(TableName, Stripped), determine_tables(Qid, Stripped)},
407 @set, set_clause_list(List),
408 ( @from, from_clause_1(F), {strip_sql_comments(F, CleanedFrom), ( determine_tables(Qid, CleanedFrom)-> From = from(F) ; otherwise->throw(failed_tables(CleanedFrom)))}
409 | {From = {no_from}}),
410 ( @where, search_condition(Where), {Condition = where(Where)} | {Condition = {no_where}}).
411set_clause_list([Head|Tail])--->
412 set_clause(Head), (@comma, set_clause_list(Tail) | {Tail = []}).
413set_clause(set(Target, Source))--->
414 update_target(Target), @equals_operator, update_source(Source). 415update_target(Target)---> column_name(Target). 416update_source(Source)---> value_expression(Source, _) | default_specification(Source, _) | null_specification(Source, _). 417insert_column_list(List)---> column_name_list(List).
418override_clause(overriding_user_value)---> @overriding, @user, @value, !.
419override_clause(overriding_system_value)---> @overriding, @system, @value, !.
420
421
422view_definition(view_definition(Name, Columns, Expression, With), Types)---> (@create), @view, table_name(Name),
423 {
424 strip_sql_comments(Name, NameNoComments),
425 ( NameNoComments = table(identifier(schema(_, literal(dbo, identifier)), _))->
426 true
427 ; otherwise->
428 throw(illegal_view_name(no_schema))
429 )},
430 ( @left_paren, view_column_list(Columns), @right_paren | {Columns = {all}}), with_attribute(With), @as, query_expression(Expression, Types).
431table_name(table(Name))---> qualified_name(Name).
432view_column_list(List)---> column_name_list(List).
433query_expression(Term, T)--->
434 qid(Qid),
435 non_join_query_term(LHS, LT),
436 ( @union, (@all, {Term = union_all(LHS, RHS, Corresponding)} | {Term = union(LHS, RHS, Corresponding)}), (corresponding_spec(Corresponding) | {Corresponding = {no_corresponding}}), set_qid(SubQid), query_expression(RHS, RT), {peer_query(Qid, SubQid), union_type(Qid, LT, RT, T)}
437 | @except, (@all, {Term = except_all(LHS, RHS, Corresponding)} | {Term = except(LHS, RHS, Corresponding)}), (corresponding_spec(Corresponding) | {Corresponding = {no_corresponding}}), query_expression(RHS, RT), {union_type(Qid, LT, RT, T)}
438 | {Term = LHS, T = LT}).
439non_join_query_term(Term, T)---> (non_join_query_primary(LHS, LT) | free_joined_table(LHS, LT)),
440 ( @intersect, ( @all, {Term = intersect_all(LHS, RHS, Corresponding)} | {Term = intersect(LHS, RHS, Corresponding)}),
441 ( corresponding_spec(Corresponding) | {Corresponding = {no_corresponding}}), non_join_query_term(RHS, RT), qid(Qid), {union_type(Qid, LT, RT, T)} | {Term = LHS, T = LT}).
442non_join_query_primary(Primary, T)---> (simple_table(Primary, T) | @left_paren, query_expression(Primary, T), @right_paren).
443simple_table(Table, T)---> query_specification(Query, T), {Table = query(Query)} | table_value_constructor(Values, T), {Table = values(Values)} | explicit_table(Explicit), {Table = explicit_table(Explicit), T = {fixme1}}.
444query_specification(select(Q, Selections, Source, Limit, For), QueryType)--->
445 @select, ( set_quantifier(Q) | {Q = {no_quantifier}} ), [ dbms('Microsoft SQL Server'), top_clause(Limit) ],
446 select_list(Selections, Sources, Types), table_expression(Source), [dbms('PostgreSQL'), limit_clause(Limit)], {var(Limit)->Limit = {no_limit} ; true},
447 ( dbms('Microsoft SQL Server'), for_clause(For), get_source(S1), {semantic_error(for_clause, S1, 2)} | {For = {no_for}}),
448 {(strip_sql_comments(Selections, S), merge_types(S, Sources, Types, QueryType)-> true ; throw(failed_to_resolve))}.
449select_list(N, S, T)---> (@asterisk, qid(Qid), get_source(Source), {N = all, find_all_column_types(Qid, Source, T1), frozen_reverse(Qid, T1, T)} | select_list_1(N, S, T)).
450select_list_1([Head|Tail], [Source|Sources], [Type|Types])---> select_sublist(Head, Source, Type), (@comma, select_list_1(Tail, Sources, Types) | {Tail = [], Sources = [], Types = []}).
451select_sublist(S, Source, Type)---> get_source(Source), derived_column(Column, Type), {S = Column} | qualifier(Qualifier), @period, @asterisk, {S = all(Qualifier), Type = {fixme3}}.
452derived_column(derived_column(Column, As), Type)---> (illegal_null_specification(Column, Type) | value_expression(Column, Type)), (as_clause(As) | {As = {no_alias}}). 453as_clause(Name)---> [@as], column_name(Name).
454table_expression(source(From, Where, GroupBy, OrderBy, Having))--->
455 from_clause(From),
456 qid(Qid),
457 {((From = _:from(F))->
458 strip_sql_comments(F, CleanedFrom),
459 ( determine_tables(Qid, CleanedFrom)-> true ; otherwise->throw(failed_tables(CleanedFrom)))
460 ; From = _:{no_from}->
461 true
462 )},
463 ( where_clause(Where) | {Where = {no_where}}),
464 ( group_by_clause(GroupBy) | {GroupBy = {no_groupby}}),
465 466 467
468 469 470 qid(Qid), set_qid(SubqueryId), {subquery(SubqueryId, Qid)},
471 ( order_by_clause(OrderBy), set_qid(Qid), (having_clause(Having) | {Having = {no_having}})
472 | set_qid(Qid), having_clause(Having), ( set_qid(SubqueryId), order_by_clause(OrderBy), get_source(Source), {semantic_error(order(having, order_by), Source, 2)} | {OrderBy = {no_orderby}})
473 | {OrderBy = {no_orderby}, Having = {no_having}}),
474 set_qid(Qid).
475from_clause(from(From))---> @from, from_clause_1(From).
476from_clause({no_from})---> {true}.
477from_clause_1([Head|Tail])---> table_reference(Head), get_source(Source), (@comma, {semantic_error(Source, deprecated('SQL89-style join', 'Explicit JOIN clauses'), 1)}, from_clause_1(Tail) | {Tail = []}).
478
479table_reference(Reference)---> (@left_paren, table_reference(LHS), @right_paren
480 | derived_table(Derivation, T), correlation_specification(Correlation), {LHS = derived_table(Derivation, Correlation, T)}
481 | table_name(Name), (correlation_specification(Correlation) | {Correlation = {no_correlation}}), {LHS = correlated_table(Name, Correlation)}),
482 [ dbms('Microsoft SQL Server'), with_clause(_) ], 483 ( more_join(RHS), {Reference = join(LHS, RHS)} | {Reference = LHS}).
484more_join(X)--->
485 ( cross_join_rhs(LHS), {Reference = cross_join(LHS)}
486 | qualified_join_rhs(Type, LHS, On), {Reference = qualified_join(Type, LHS, On)}),
487 ( more_join(RHS2), {X = join(Reference, RHS2)} | {X = Reference}).
488correlation_specification(correlation(Name, Columns))---> [@as], #NameMC, (@left_paren, derived_column_list(Columns), @right_paren | {Columns = {no_columns}}), {name_from_identifier(NameMC, Name)}.
489derived_column_list(L)--->column_name_list(L).
490derived_table(Table, T)---> table_subquery(Table, T).
491table_subquery(Query, T)---> subquery(Query, T).
492cross_join_rhs(Reference)---> @cross, @join, table_reference(Reference).
493qualified_join_rhs(Type, Reference, Spec)---> ( @natural, {Type = natural(T1)} | {Type = T1} ), ( join_type(T1) | {T1 = join} ), (@join), table_reference(Reference), ( join_specification(Spec) | {Spec = {no_on}} ).
494free_joined_table(Table, {fixme4})---> table_reference(Table).
495join_type(join_type(Type))---> (@inner, {Type = inner} | outer_join_type(T1), {Type = outer(T1)}, [ @outer ] | @union, {Type = union}).
496outer_join_type(T)---> (@left, {T=left} | @right, {T=right} | @full, {T=full}).
497join_specification(Spec)---> ( join_condition(Spec) | named_columns_join(Spec) ).
498join_condition(on(On)) ---> @on, search_condition(On).
499named_columns_join(columns(Columns))---> @using, @left_paren, join_column_list(Columns), @right_paren.
500join_column_list(Columns)---> column_name_list(Columns).
501set_quantifier(Q)---> ( @distinct, {Q = distinct} | @all, {Q = all} ).
502where_clause(where(Where))---> @where, search_condition(Where).
503corresponding_spec(Columns)---> @corresponding, ( @by, @left_paren, corresponding_column_list(Columns), @right_paren | {Columns = {no_columns}} ).
504corresponding_column_list(List)---> column_name_list(List).
505query_primary(Primary, T)---> ( non_join_query_primary(Primary, T) | free_joined_table(Primary, T) ).
506subquery(subquery(Query), T)---> (@left_paren, add_option(subquery), qid(Qid), set_qid(SubqueryId), {subquery(Qid, SubqueryId)}, query_expression(Query, T), @right_paren).
507column_name_list([Head|Tail])---> column_name(Head), (@comma, column_name_list(Tail) | {Tail = []}).
508column_name(Name)---> #Identifier, \+(@left_paren),
509 {( Identifier = literal(Name, identifier)->
510 true
511 ; Identifier = literal(A,B)-> 512 Name = literal(A,B)
513 ; otherwise->
514 downcase_atom(Identifier, Name)
515 )}.
516explicit_table(table(Table)) ---> @(table), table_name(Table).
517qualifier(Qualifier)---> qualified_name(Qualifier).
521value_expression(V, T)---> numeric_value_expression(V, T), \+(@concatenation_operator), \+(@minus_sign), \+(@period) 522 | string_value_expression(V, T), \+(@concatenation_operator), \+(@minus_sign), \+(@period)
523 | datetime_value_expression(V, T)
524 | interval_value_expression(V, T).
525
527
528numeric_value_expression(V, T)--->
529 numeric_value_expression_1(V, T1),
530 qid(Qid),
531 {left_factor_types(Qid, T1, T)}.
532
533numeric_value_expression_1(V, T)--->
534 get_source(LS), term(LHS, LT), qid(Qid),
535 ( ( @plus_sign, {Op = add} | @minus_sign, {Op = subtract} ),
536 get_source(RS),
537 numeric_value_expression_1(RHS, RT),
538 {T = node(LT, LS, Op, RT, RS),
539 540 541 542 543 left_factor_types(Qid, RT, R1),
544 left_factor_types(Qid, LT, L1),
545 most_general_type(Qid, Source, Source, L1, R1, Op, T1),
546 freeze(T1, determine_operation_from_types(T1, L1, R1, Op, LHS, RHS, V))}
547 | {V = LHS, T = LT}
548 ).
549
550
552determine_operation_from_types(Type, LT, RT, Op, LHS, RHS, V):-
553 554 native_type_of_type(LT, LTT),
555 native_type_of_type(RT, RTT),
556 ( Op == add ->
557 ( native_type_of_type(Type, native_type(varchar(_)))->
558 V = concatenate(LHS, RHS)
559 ; native_type_of_type(Type, native_type(nvarchar(_)))->
560 V = concatenate(LHS, RHS)
561 ; LTT = native_type(datetime),
562 RTT = native_type(int(_))->
563 V = add_interval(LHS, RHS)
564 ; RTT = native_type(datetime),
565 LTT = native_type(int(_))->
566 V = add_interval(RHS, LHS)
567 568 569 ; LTT = native_type(datetime),
570 RTT = native_type(decimal(_,_))->
571 V = add_interval(LHS, RHS)
572 ; otherwise->
573 V = add(LHS, RHS)
574 )
575 ; Op == subtract ->
576 ( LTT = native_type(datetime),
577 RTT = native_type(int(_))->
578 V = add_interval(LHS, negative(RHS))
579 ; RTT = native_type(datetime),
580 LTT = native_type(int(_))->
581 V = add_interval(RHS, negative(LHS))
582 583 584 ; LTT = native_type(datetime),
585 RTT = native_type(decimal(_,_))->
586 V = add_interval(LHS, negative(RHS))
587 ; otherwise->
588 V = subtract(LHS, RHS)
589 )
590 ).
591
592
593native_type_of_type(native_type(X), native_type(X)):- !.
594native_type_of_type(domain(D), native_type(X)):-
595 fetch_domain_data_type(D, X).
596
597term(V, T)---> get_source(LS), factor(LHS, LT), ((@asterisk, {V = multiply(LHS, RHS), Op = multiply} | @solidus, {V = divide(LHS, RHS), Op = divide(RT)}), get_source(RS), term(RHS, RT), {T = node(LT, LS, Op, RT, RS)} | {V = LHS, T = LT}).
598factor(V, T)---> ( (@plus_sign, {V = positive(N)} | @minus_sign, dbms(DBMS), {V = negative(N), (DBMS == 'Microsoft SQL Server' -> force_type_not_domain(T) ; true)}) | { V = N} ), numeric_primary(N, T). 599numeric_primary(N, T)---> value_expression_primary(N, T) | numeric_value_function(N, T).
600value_expression_primary(N, T)--->
601 unsigned_value_specification(N, T) | parameter(N, T) | column_reference(N, T) | set_function_specification(N, T) | case_expression(N, T) | @left_paren, value_expression(N, T), @right_paren | cast_specification(N, T) | scalar_subquery(N, T) | routine_invocation(N, T).
602parameter(parameter(N), native_type(int)) ---> @(?), get_parameter(N). 603column_reference(column(Qualifier, Name), Type)---> ( qualifier(Qualifier), @period | {Qualifier = {no_qualifier}} ), column_name(Name), qid(Qid), get_source(Source), {strip_sql_comments(Qualifier, QS), strip_sql_comments(Name, NS), type_constraint(Qid, Source, Type, typeof(QS, NS)), type_constraint_ready(Qid, Type)}.
604scalar_subquery(S, T)---> subquery(S, ST), qid(Qid), get_source(Source), {type_constraint(Qid, Source, T, scalar(ST)), type_constraint_ready(Qid, T)}.
605having_clause(having(Having))---> @having, search_condition(Having).
606group_by_clause(group_by(List))---> @group, @by, grouping_column_reference_list(List).
607grouping_column_reference_list([Head|Tail])---> grouping_column_reference(Head), ( @comma, grouping_column_reference_list(Tail) | {Tail = []} ).
608grouping_column_reference(group_column(Reference, Collate))---> column_reference(Reference, _), ( collate_clause(Collate) | {Collate = {no_collation}} ).
609collate_clause(collate(Name))---> @collate, collation_name(Name).
610collation_name(collation(Name))---> qualified_name(Name).
611qualified_name(identifier(Qualifier, Name))---> ( schema_name(Qualifier), @period | {Qualifier = {no_schema}}), #Identifier, {name_from_identifier(Identifier, Name)}. 612schema_name(schema(Catalog, Schema))---> ( catalog_name(Catalog), @period | {Catalog = {no_catalog}}), #Schema.
613catalog_name(Catalog)---> #Catalog.
614set_function_specification(S, T)---> (@count, @left_paren, @asterisk, @right_paren, {S = count(all), T = native_type(int)} | general_set_function(S, T)).
615set_function_specification(S, T)---> (@count_big, @left_paren, @asterisk, @right_paren, {S = count(all), T = native_type(bigint)} | general_set_function(S, T)).
616
617general_set_function(set_function(S, Q, A), T)---> set_function_type(S), @left_paren, ( set_quantifier(Q) | {Q = {no_quantifier}} ), value_expression(A, AT), @right_paren, qid(Qid), get_source(Source),
618 {S = _:count ->
619 T = native_type(int)
620 ; S = _:sum->
621 type_merge_hint(T, sum),
622 type_constraint(Qid, Source, T, AT),
623 type_constraint_ready(Qid, T)
624 ; S = _:avg->
625 type_merge_hint(T, avg),
626 type_constraint(Qid, Source, T, AT),
627 type_constraint_ready(Qid, T)
628 ; otherwise->
629 T = AT
630 }.
631set_function_type(T)---> @avg, {T = avg} | @max, {T = max} | @min, {T = min} | @sum, {T = sum} | @count, {T = count}.
632search_condition(C, _Types)---> search_condition(C).
633search_condition(C)---> boolean_term(Head), (@or, search_condition(Tail), {C = or(Head, Tail)} | {C = Head}).
634boolean_term(C)---> boolean_factor(Head), (@and, boolean_term(Tail), {C = and(Head, Tail)} | {C = Head}).
635boolean_factor(C)---> ( @not, {C = not(X)} | {C = X} ), boolean_test(X).
636boolean_test(Test)---> boolean_primary(X), ( @is_keyword, ( @not, {Test = isnot(X, T)} | {Test = is(X, T)}), truth_value(T) | {Test = X}).
637truth_value(T)---> (@true, {T = true} | @false, {T = false} | @unknown, {T = unknown}).
638boolean_primary(P)---> @left_paren, search_condition(Search), {P = search(Search)}, @right_paren | predicate(Pr), {P = predicate(Pr)}.
639predicate(Predicate)---> comparison_predicate(Predicate) | between_predicate(Predicate) | in_predicate(Predicate) | like_predicate(Predicate) | null_predicate(Predicate) | quantified_comparison_predicate(Predicate) | exists_predicate(Predicate) | match_predicate(Predicate) | overlaps_predicate(Predicate).
640comparison_predicate(comparison(CompOp, LHS, RHS))---> row_value_constructor(LHS, LT), comp_op(CompOp), row_value_constructor(RHS, RT), {check_types(LT, RT)}.
641row_value_constructor(Row, Types)---> @left_paren, row_value_constructor_list(List, Types), {Row = list(List)}, @right_paren | row_value_constructor_element(Element, Types), {Row = element(Element)} | row_subquery(SubQuery, Types), {Row = query(SubQuery, Types)}.
642row_value_constructor_element(Element, Type)---> value_expression(Element, Type) | null_specification(Element, Type) | default_specification(Element, Type).
643comp_op(Op)---> @equals_operator, {Op = '='}
644 | @not_equals_operator, {Op = '<>'}
645 | @less_than_operator, {Op = '<'}
646 | @greater_than_operator, {Op = '>'}
647 | @less_than_or_equals_operator, {Op = '<='}
648 | @greater_than_or_equals_operator, {Op = '>='}.
649null_specification({null}, T)---> @null, qid(Qid), get_source(Source), {type_constraint(Qid, Source, T, {nulltype}), type_constraint_ready(Qid, T)}.
650illegal_null_specification({null}, T)---> @null, qid(Qid), get_source(Source), {semantic_error(Source, null_value, 1), type_constraint(Qid, Source, T, {nulltype}), type_constraint_ready(Qid, T)}.
651null_predicate(Predicate)---> row_value_constructor(LHS, _), @is_keyword, ( @not, {Predicate = is_not_null(LHS)} | {Predicate = is_null(LHS)} ), @null. 652default_specification({default}, {defaulttype})---> @default.
653row_subquery(S, T)---> subquery(S, T).
654row_value_constructor_list([Head|Tail], [Type|Types])---> row_value_constructor_element(Head, Type), (@comma, row_value_constructor_list(Tail, Types) | {Tail = [], Types = []}) .
655between_predicate(Term)---> row_value_constructor(LHS, TA), ( @not, {Term = not_between(LHS, Min, Max)} | {Term = between(LHS, Min, Max)}), @between, row_value_constructor(Min, TB), @and, row_value_constructor(Max, TC), {check_types(TA, TB), check_types(TA, TC)}.
656exists_predicate(exists(Query))---> @exists, table_subquery(Query, _).
657in_predicate(P) ---> row_value_constructor(Value, T1), ( @not, {P = not_in(Value, List)} | {P = in(Value, List)} ), @in, in_predicate_value(List, T2), {forall(member(T, T2), check_types(T1, T))}.
658in_predicate_value(In, Types)---> @left_paren, in_value_list(List, Types), {In = list(List)}, @right_paren | table_subquery(Query, Types), {In = query(Query)}.
659in_value_list([Head|Tail], [Type|Types])---> value_expression(Head, Type), ( @comma, in_value_list(Tail, Types) | {Tail = [], Types = []} ).
660like_predicate(P)---> match_value(LHS), ( @not, {P = not_like(LHS, Pattern, Escape)} | {P = like(LHS, Pattern, Escape)}), (@like | @ilike), pattern(Pattern), ( @escape, escape_character(Escape) | {Escape = {no_escape}}).
661match_value(P)---> character_value_expression(P, _).
662pattern(P)---> character_value_expression(P, _).
663escape_character(P)---> character_value_expression(P, _).
664character_value_expression(E, T)---> get_source(S1), character_factor(LHS, LT), (@concatenation_operator, get_source(S2), character_value_expression(RHS, RT), qid(Qid), {E = concatenate(LHS, RHS), concatenate_type(Qid, S1, S2, LT, RT, T)} | {E = LHS, T = LT}).
665character_factor(Factor, T)---> character_primary(F, T), ( collate_clause(C), {Factor = collated_factor(F, C)} | {Factor = F} ).
666character_primary(X, T)---> value_expression_primary(X, T) | string_value_function(X, T).
667match_predicate(match(Unique, MatchLevel, LHS, RHS))---> row_value_constructor(LHS, TL), @match, [ @unique, {Unique = unique} ], [ (@partial, {MatchLevel = partial} | @full, {MatchLevel = full}) ], table_subquery(RHS, TR), {check_types(TL, TR)}.
668overlaps_predicate(overlaps(LHS, RHS))---> row_value_constructor(LHS, TL), @overlaps, row_value_constructor(RHS, TR), {check_types(TL, TR)}.
669quantified_comparison_predicate(quantified_comparison(Op, Quantifier, LHS, RHS))---> row_value_constructor(LHS, TL), comp_op(Op), quantifier(Quantifier), table_subquery(RHS, TR), {check_types(TL, TR)}.
670quantifier(Quantifier)---> @all, {Quantifier = all} | @some, {Quantifier = some}.
671table_value_constructor(N, T)---> @values, table_value_constructor_list(N, T).
672table_value_constructor_list([Head|Tail], [Type|Types])---> row_value_constructor(Head, Type), (@comma, table_value_constructor_list(Tail, Types) | {Tail = [], Types = []}).
673case_expression(N, T)---> case_abbreviation(N, T) | case_specification(N, T).
674case_abbreviation(V, T)---> @nullif, @left_paren, value_expression(LHS, LT), @comma, value_expression(RHS, RT), @right_paren, qid(Qid), get_source(Source), {V = nullif(LHS, RHS), most_general_type(Qid, Source, Source, LT, RT, case, T)}
675 | @coalesce, @left_paren, coalesce_list(List, Types, Sources), @right_paren, qid(Qid), {V = coalesce(List), coalesce_type(Qid, Types, Sources, T)}.
676coalesce_list([Head|Tail], [Type|Types], [Source|Sources])---> get_source(Source), (null_specification(Head, Type), get_source(Source), {semantic_error(Source, coalesce(null_argument), 1)} | value_expression(Head, Type)), ( @comma, coalesce_list(Tail, Types, Sources) | {Tail = [], Types = [], Sources = []} ).
677case_specification(N, T)---> searched_case(N, T) | simple_case(N, T).
678simple_case(simple_case(Operand, List, Else), T)---> @case, qid(Qid), case_operand(Operand), simple_when_clause_list(List, Types, Sources), ( get_source(Source), else_clause(Else, ElseType), {coalesce_type(Qid, [ElseType|Types], [Source|Sources], T)} | {Else = {no_else}, coalesce_type(Qid, Types, Sources, T)} ), @end.
679simple_when_clause_list([Head|Tail], [Type|Types], [Source|Sources])---> get_source(Source), simple_when_clause(Head, Type), (simple_when_clause_list(Tail, Types, Sources) | {Tail = [], Types = [], Sources = []}).
680case_operand(X)---> value_expression(X, _).
681simple_when_clause(when(When, Result), T)---> @when, when_operand(When), @then, result(Result, T).
682when_operand(X)---> value_expression(X, _).
683result(X, T)---> null_specification(X, T) | result_expression(X, T).
684result_expression(X, T)---> value_expression(X, T).
685else_clause(else(Else), T)---> @else, result(Else, T).
686searched_case(case(Cases, Else), T)---> @case, qid(Qid), searched_when_clause_list(Cases, Types, Sources), ( get_source(Source), else_clause(Else, ElseT), {coalesce_type(Qid, [ElseT|Types], [Source|Sources], T)} | {Else = {no_else}, force_type_not_domain(T), coalesce_type(Qid, Types, Sources, T)} ), (@end).
687searched_when_clause_list([Head|Tail], [Type|Types], [Source|Sources])---> get_source(Source), searched_when_clause(Head, Type), (searched_when_clause_list(Tail, Types, Sources) | {Tail = [], Types = [], Sources = []}).
688searched_when_clause(when(searched(Search), Result), T)---> @when, search_condition(Search), @then, result(Result, T).
689numeric_value_function(N, native_type(int))---> position_expression(N) | extract_expression(N) | length_expression(N).
690position_expression(position(A, B))---> @position, @left_paren, character_value_expression(A, _), @in, character_value_expression(B, _), @right_paren.
691extract_expression(extract(Field, Source))---> @extract, @left_paren, extract_field(Field), @from, extract_source(Source), @right_paren.
692length_expression(A)---> char_length_expression(A) | octet_length_expression(A) | bit_length_expression(A).
693char_length_expression(char_length(A))---> ( @char_length | @character_length ), @left_paren, string_value_expression(A, _), @right_paren.
694string_value_expression(X, T)---> character_value_expression(X, T) | bit_value_expression(X, T).
695octet_length_expression(octet_length(A))---> @octet_length, @left_paren, string_value_expression(A, _), @right_paren.
696bit_length_expression(bit_length(A))---> @bit_length, @left_paren, string_value_expression(A, _), @right_paren.
697extract_field(Field)---> datetime_field(Field) | time_zone_field(Field).
698extract_source(V)---> datetime_value_expression(V, _) | interval_value_expression(V, _).
699unsigned_value_specification(Value, native_type(int(X)))---> #Value : int(X).
700routine_invocation(routine(Name, Args), Type)---> qualified_name(Name), @left_paren, dbms(DBMS), {not_a_builtin_function(DBMS, Name)}, (sql_argument_list(Args) | {Args = []}), @right_paren, {routine_type(Name, Type)}.
701sql_argument_list([Head|Tail])---> sql_argument(Head), (@comma, sql_argument_list(Tail) | {Tail = []}).
702sql_argument(Arg)---> value_expression(Arg, _).
703cast_specification(cast(Operand, Target), Type)---> @cast, @left_paren, cast_operand(Operand), @as, cast_target(Target), {strip_sql_comments(Target, Type)}, @right_paren.
704cast_operand(Operand)---> @null, {Operand = {null}} | value_expression(Operand, _).
705cast_target(Target)---> data_type(Type), {Target = native_type(Type)} | domain_name(Domain), {Target = domain(Domain)}.
706domain_name(Name)---> qualified_name(Name).
707data_type(Type)---> character_string_type(Type), ( @character, @set, character_set_specification(_) | {true}) | national_character_string_type(Type) | bit_string_type(Type) | numeric_type(Type) | datetime_type(Type) | interval_type(Type).
708character_string_type(varchar(Length))---> @character, ( @left_paren, length(Length), @right_paren | {Length = 30})
709 | @char, ( @left_paren, length(Length), @right_paren | {Length = 30})
710 | @character, @varying, ( @left_paren, length(Length), @right_paren | {Length = 30})
711 | @char, @varying, ( @left_paren, length(Length), @right_paren | {Length = 30})
712 | @varchar, ( @left_paren, length(Length), @right_paren | {Length = 30}).
713length(Length)---> #Length : int(_) | (@max, {Length = max}).
714national_character_string_type(nchar_type(Length))--->
715 @national, @character, [ @left_paren, length(Length), @right_paren ]
716 | @national, @char, [ @left_paren, length(Length), @right_paren ]
717 | @nchar, [ @left_paren, length(Length), @right_paren ]
718 | @national, @character, @varying, [ @left_paren, length(Length), @right_paren ]
719 | @national, @char, @varying, [ @left_paren, length(Length), @right_paren ]
720 | @nchar, @varying, [ @left_paren, length(Length), @right_paren ].
721bit_string_type(bit_type(Length))---> @bit, [ @left_paren, length(Length), @right_paren ] | @bit, @varying, [ @left_paren, length(Length), @right_paren ].
722numeric_type(Type)---> exact_numeric_type(Type) | approximate_numeric_type(Type).
723exact_numeric_type(Type)---> @numeric, {Type = decimal(Precision, Scale)}, ( @left_paren, precision(Precision), ( @comma, scale(Scale) | {Scale = {no_scale}}), @right_paren | default_precision_and_scale(Precision, Scale))
724 | @decimal, {Type = decimal(Precision, Scale)}, ( @left_paren, precision(Precision), ( @comma, scale(Scale) | {Scale = {no_scale}}), @right_paren | default_precision_and_scale(Precision, Scale) )
725 | @dec, {Type = decimal(Precision, Scale)}, ( @left_paren, precision(Precision), ( @comma, scale(Scale) | {Scale = {no_scale}}), @right_paren | default_precision_and_scale(Precision, Scale) )
726 | @integer, {Type = int}
727 | @int, {Type = int}
728 | @smallint, {Type = smallint}
729 | dbms('Microsoft SQL Server'), @tinyint, {Type = tinyint}.
730precision(Precision)---> #Precision : int(_).
731scale(Scale)---> #Scale : int(_).
732approximate_numeric_type(Type)---> @float, ( @left_paren, precision(Precision), @right_paren | {Precision = {no_precision}}), {Type = float(Precision)} | @real, {Type = real} | @double, precision(Precision), {Type = double(Precision)}.
733datetime_value_expression(V, T)---> (datetime_term(LHS, LT) | interval_value_expression(LHS, LT)),
734 ( ( @plus_sign, {V = add(LHS, RHS), Op = add} | @minus_sign, {V = subtract(LHS, RHS), Op = subtract}), datetime_value_expression(RHS, RT), qid(Qid), get_source(Source), {most_general_type(Qid, Source, Source, LT, RT, Op, T)} | {V = LHS, T = LT}).
735order_by_clause(order_by(List))---> @order, @by, get_source(Source), check_order_by_is_in_top_query(Source), sort_specification_list(List).
736sort_specification_list([Head|Tail])---> sort_specification(Head), ( @comma, sort_specification_list(Tail) | {Tail = []}).
737sort_specification(sort_key(Key, Collate, Order))---> sort_key(Key), ( collate_clause(Collate) | {Collate = {no_collation}} ), ( ordering_specification(Order) | {Order = {no_order}} ).
740sort_key(Key)---> value_expression(C, _), {Key = sort_column(C)} | #I : int(_), {Key = index(I)}.
741ordering_specification(S)---> @asc, {S = asc} | @desc, {S = desc}.
742
743interval_term(V, T)---> interval_factor(LHS, LT), (((@asterisk, {V = multiply(LHS, RHS), Op = multiply} | @solidus, {V = divide(LHS, RHS), Op = divide(RT)}), interval_term(RHS, RT), qid(Qid), get_source(Source), {most_general_type(Qid, Source, Source, LT, RT, Op, T)}) | {V = LHS, T = LT})
744 | term(LHS, LT), @asterisk, interval_factor(RHS, RT), qid(Qid), get_source(Source), {T = multiply(LHS, RHS), most_general_type(Qid, Source, Source, LT, RT, multiply, T)}.
745interval_factor(F, T)---> (@plus_sign, {F = positive(F1)} | @minus_sign, {F = negative(F1)} | {F = F1}), interval_primary(F1, T).
746interval_primary(interval(P, Q), T)---> value_expression_primary(P, T), ( interval_qualifier(Q) | {Q = {no_qualifier}} ).
747interval_value_expression(V, T)---> interval_term(LHS, LT), (((@plus_sign, {V = add(LHS, RHS), Op = add} | @minus_sign, {V = subtract(LHS, RHS), Op = subtract}), interval_term(RHS, RT), qid(Qid), get_source(Source), {most_general_type(Qid, Source, Source, LT, RT, Op, T)}) | {V = LHS, T = LT})
748 | @left_paren, datetime_value_expression(LHS, LT), @minus_sign, datetime_term(RHS, RT), @right_paren, interval_qualifier(Q), qid(Qid), get_source(Source), {T = qualified_subtract(Q, LHS, RHS), most_general_type(Qid, Source, Source, LT, RT, subtract, T)}.
749datetime_term(V, T)---> datetime_factor(V, T).
750datetime_factor(V, T)---> datetime_primary(P, T1), ( time_zone(TZ), qid(Qid), get_source(Source), {V = date_with_timezone(P, TZ), most_general_type(Qid, Source, Source, datetime_with_timezone, T1, add, T)} | {V = P, T = T1}).
751datetime_primary(V, T)---> value_expression_primary(V, T) | datetime_value_function(V, T).
752time_zone(T)---> @at, time_zone_specifier(T).
753time_zone_specifier(time_zone(T))---> @local, {T = local} | @time, @zone, interval_value_expression(T, _).
754time_zone_field(T)---> (@timezone_hour, {T = timezone_hour} | @timezone_minute, {T = timezone_minute}).
755
756datetime_type(T)---> @date, {T = date}
757 | @time, ( @left_paren, time_precision(P), @right_paren | {P = {no_precision}}), [ @with, @time, @zone], {T = time(P)}
758 | @timestamp, ( @left_paren, timestamp_precision(P), @right_paren | {P = {no_precision}}), [ @with, @time, @zone], {T = timestamp(P)}.
759time_precision(P)---> precision(P).
760timestamp_precision(P)---> precision(P).
761character_set_specification(P) ---> #P.
762
763
765datetime_field(_)---> {fail}.
766interval_qualifier(_)---> {fail}.
767interval_type(_)---> {fail}.
768string_value_function(_, _)---> {fail}.
769bit_value_expression(_, _)---> {fail}.
770
772:-discontiguous(string_value_function/8). 773string_value_function(ltrim(S), T)---> dbms('Microsoft SQL Server'), @ltrim, @left_paren, value_expression(S, T), @right_paren.
774string_value_function(rtrim(S), T)---> dbms('Microsoft SQL Server'), @rtrim, @left_paren, value_expression(S, T), @right_paren.
775string_value_function(left(S, N), T)---> dbms('Microsoft SQL Server'), @left, @left_paren, value_expression(S, ST), @comma, numeric_value_expression(N, _), @right_paren, get_source(Source), sized_varchar_type(N, Source, ST, T).
776string_value_function(right(S, N), T)---> dbms('Microsoft SQL Server'), @right, @left_paren, value_expression(S, ST), @comma, numeric_value_expression(N, _), @right_paren, get_source(Source), sized_varchar_type(N, Source, ST, T).
777string_value_function(isnull(P, C), T)---> dbms('Microsoft SQL Server'), @isnull(Source), {semantic_error(Source, deprecated(isnull, coalesce), 1)}, @left_paren, value_expression(P, T), @comma, value_expression(C, _), @right_paren. 778string_value_function(replace(S, M, R), T)---> dbms('Microsoft SQL Server'), @replace, @left_paren, string_value_expression(S, ST), @comma, string_value_expression(M, _), @comma, string_value_expression(R, _), @right_paren,
779 get_source(Source),
780 {type_merge_hint(T, max),
781 type_constraint(Qid, Source, T, native_type(varchar(8000))),
782 type_constraint(Qid, Source, T, ST)}.
783
784 string_value_function(upper(S), T)---> dbms('Microsoft SQL Server'), @upper, @left_paren, value_expression(S, T), @right_paren.
785string_value_function(lower(S), T)---> dbms('Microsoft SQL Server'), @lower, @left_paren, value_expression(S, T), @right_paren.
786string_value_function(substring(Source, Start, Length), T)--->
787 dbms('Microsoft SQL Server'), @substring, @left_paren, character_value_expression(Source, ST), @comma, numeric_value_expression(Start, _), @comma, numeric_value_expression(Length, _), @right_paren, get_source(Source), sized_varchar_type(Length, Source, ST, T).
788string_value_function(datename(Type, Source), varchar) ---> dbms('Microsoft SQL Server'), @datename, @left_paren, sql_server_date_part(Type), @comma, datetime_value_expression(Source, _), @right_paren.
789string_value_function(dbname({}), native_type(nvarchar(128)))---> dbms('Microsoft SQL Server'), @db_name, @left_paren, @right_paren.
790string_value_function(permissions(S), varchar)---> dbms('Microsoft SQL Server'), @permissions, @left_paren, character_value_expression(S, _), @right_paren.
791string_value_function(username(String), native_type(nvarchar(128)))---> dbms('Microsoft SQL Server'), @user_name, @left_paren, character_value_expression(String, _), @right_paren.
792string_value_function(str(S), T)---> dbms('Microsoft SQL Server'), @str, @left_paren, qid(Qid), get_source(Source), {type_merge_hint(T, str), type_constraint(Qid, Source, T, native_type(varchar(1))), type_constraint(Qid, Source, T, ST)}, numeric_value_expression(S, ST), @right_paren.
793
794:-discontiguous(datetime_value_function/8). 795datetime_value_function(dateadd(Type, N, Source), native_type(datetime))---> dbms('Microsoft SQL Server'), @dateadd, @left_paren, sql_server_date_part(Type), @comma, numeric_value_expression(N, _), @comma, datetime_value_expression(Source, _), @right_paren.
796
797:-discontiguous(numeric_value_function/8). 798numeric_value_function(current_timestamp, native_type(datetime))---> @current_timestamp.
799numeric_value_function(getdate({}), native_type(datetime))---> dbms('Microsoft SQL Server'), @getdate, @left_paren, @right_paren.
800numeric_value_function(fn_now({}), native_type(datetime))---> dbms('Microsoft SQL Server'), @left_curly, @fn, @now, @left_paren, @right_paren, @right_curly, get_source(Source), {semantic_error(sql_escape, Source, 1)}.
801numeric_value_function(isnull(P, C), T)---> dbms('Microsoft SQL Server'), @isnull(Source), {semantic_error(Source, deprecated(isnull, coalesce), 1)}, @left_paren, value_expression(P, T), @comma, value_expression(C, _), @right_paren.
802numeric_value_function(datediff(Type, LHS, RHS), native_type(int))---> dbms('Microsoft SQL Server'), @datediff, @left_paren, sql_server_date_part(Type), @comma, datetime_value_expression(LHS, _), @comma, numeric_value_expression(RHS, _), @right_paren.
803numeric_value_function(day(S), native_type(int))---> dbms('Microsoft SQL Server'), @day, @left_paren, datetime_value_expression(S, _), @right_paren.
804numeric_value_function(month(S), native_type(int))---> dbms('Microsoft SQL Server'), @month, @left_paren, datetime_value_expression(S, _), @right_paren.
805numeric_value_function(year(S), native_type(int))---> dbms('Microsoft SQL Server'), @year, @left_paren, datetime_value_expression(S, _), @right_paren.
806
807numeric_value_function(datepart(Type, S), native_type(int))---> dbms('Microsoft SQL Server'), @datepart, @left_paren, sql_server_date_part(Type), @comma, datetime_value_expression(S, _), @right_paren.
808numeric_value_function(charindex(Source, Search, Start), native_type(int))---> dbms('Microsoft SQL Server'), @charindex, @left_paren, character_value_expression(Source, _), @comma, string_value_expression(Search, _), ( @comma, numeric_value_expression(Start, _) | {Start = {no_start}}), @right_paren.
809numeric_value_function(len(Source), native_type(int))---> dbms('Microsoft SQL Server'), @len, @left_paren, character_value_expression(Source, _), @right_paren.
810numeric_value_function(abs(S), T)---> dbms('Microsoft SQL Server'), @abs, @left_paren, {force_type_not_domain(T)}, numeric_value_expression(S, T), @right_paren.
811numeric_value_function(round(S, P), T)---> dbms('Microsoft SQL Server'), @round, @left_paren, {force_type_not_domain(T)}, numeric_value_expression(S, T), @comma, numeric_value_expression(P, _), @right_paren.
812numeric_value_function(floor(S), T)---> dbms('Microsoft SQL Server'), @floor, @left_paren, numeric_value_expression(S, ST), @right_paren, qid(Qid), get_source(Source), {type_merge_hint(T, round), type_constraint(Qid, Source, T, ST), type_constraint_ready(Qid, T)}.
813numeric_value_function(ceiling(S), native_type(int))---> dbms('Microsoft SQL Server'), @ceiling, @left_paren, numeric_value_expression(S, _), @right_paren.
814sql_server_date_part(T)---> ( @year | @yy | @yyyy), {T = year}
815 | (@quarter | @qq | @q ), {T = quarter}
816 | (@month | @mm | @m), {T = month}
817 | (@dayofyear | @dy), {T = dayofyear}
818 | (@day | @dd | @d | #literal(day, _), get_source(Source), {semantic_error(superfluous_quote(day), Source, 1)}), {T = day}
819 | (@week | @wk | @ww), {T = week}
820 | (@weekday | @dw | @w), {T = weekday}
821 | (@hour | @hh), {T = hour}
822 | (@minute | @mi | @n), {T = minute}
823 | (@second | @ss | @s), {T = second}
824 | (@millisecond | @ms), {T = millisecond}
825 | (@microsecond | @mcs), {T = microsecond}
826 | (@nanosecond | @ns), {T = nanosecond}.
827
828
829:-discontiguous(cast_specification/8). 830cast_specification(precision_cast(Target, Operand, P), Type)---> dbms('Microsoft SQL Server'), @convert, @left_paren, cast_target(Target), @comma, cast_operand(Operand), ( @comma, precision(P) | {P = {no_precision}} ), @right_paren, {strip_sql_comments(Target, Type)}.
831
832top_clause(top(N))---> @top, numeric_value_expression(NN, _T), ( @percent, get_source(Source), {semantic_error(percent, Source, 1)}, {N = percent(NN)} | {N = NN}). 833limit_clause(top(N))---> @limit, numeric_value_expression(N, _T). 834
835with_attribute(With)---> @with, @schemabinding, {With = with(schemabinding)} 836 | {With = {no_with}}. 837
838with_clause(with(nolock))---> @with, @left_paren, @nolock, @right_paren.
839with_clause(with(noexpand))---> @with, @left_paren, @noexpand, @right_paren. 840
841for_clause(for(xml_path(I)))---> @for, @xml, @path, @left_paren, string_value_expression(I, _), @right_paren, qid(Q), {query_is_xml(Q)}.
842:-discontiguous(grouping_column_reference/7). 843grouping_column_reference(group_expression(Expression, Collate))---> dbms('Microsoft SQL Server'), value_expression(Expression, _), ( collate_clause(Collate) | {Collate = {no_collation}} ).
844:-discontiguous(sort_key/7). 845sort_key(sort_expression(Expression))---> dbms('Microsoft SQL Server'), value_expression(Expression, _).
846
847:-discontiguous(datetime_type/7). 848datetime_type(datetime)---> @datetime.
849
850
851sized_varchar_type(L, L, O, O, P0, P0, Length, Source, SourceT, T):-
852 memberchk(query_id(Qid), O),
853 strip_sql_comments(Length, LS),
854 ( integer(LS) ->
855 856 type_merge_hint(T, sized_varchar),
857 type_constraint(Qid, Source, T, native_type(varchar(LS))),
858 type_constraint(Qid, Source, T, SourceT)
859 ; otherwise->
860 force_type_not_domain(T),
861 type_constraint(Qid, Source, T, SourceT),
862 type_constraint_ready(Qid, T)
863 ).
864
865sql_explain(_).
866user:goal_expansion(sql_explain(_), true).
868
869remove_quoted_column @
870 type_constraint(QueryId, Source, Type, typeof(identifier(A, B), literal(ColumnName, string)))
871 <=>
872 type_constraint(QueryId, Source, Type, typeof(identifier(A, B), ColumnName)).
873
874define_type_from_subquery @
875 derived_query_column(QueryId, TableAlias, Column, DerivedType)
876 \
877 type_constraint(QueryId, Source, Type, typeof(identifier(_, TableAlias), Column))
878 <=>
879 type_constraint(QueryId, Source, Type, DerivedType).
880
881define_type_from_subquery_with_unspecified_column @
882 derived_query_column(QueryId, _, Column, DerivedType)
883 \
884 type_constraint(QueryId, Source, Type, typeof({no_qualifier}, Column))
885 <=>
886 type_constraint(QueryId, Source, Type, DerivedType).
887
888
889define_type_from_literal @
890 type_constraint(QueryId, Source, Type, typeof({no_qualifier}, literal(Literal, Kind)))
891 <=>
892 ( Literal == '' ->
893 ColumnType = native_type(varchar(1)) 894 ; Kind == string->
895 atom_length(Literal, L),
896 ColumnType = native_type(varchar(L))
897 ; otherwise->
898 ColumnType = native_type(Kind)
899 ),
900 type_constraint(QueryId, Source, Type, ColumnType).
901
902define_type_from_query @
903 query_table(QueryId, TableAlias, identifier(_, TableName))
904 \
905 type_constraint(QueryId, Source, Type, typeof(identifier(_, TableAlias), SourceColumnName))
906 <=>
907 default_schema(Schema),
908 fetch_database_attribute(_, Schema, TableName, SourceColumnName, ColumnType, _, _, _)
909 |
910 type_constraint(QueryId, Source, Type, ColumnType).
911
912define_type_from_query_with_unnamed_table @
913 query_table(QueryId, _, identifier(_, TableName))
914 \
915 type_constraint(QueryId, Source, Type, typeof({no_qualifier}, SourceColumnName))
916 <=>
917 918 default_schema(Schema),
919 920 fetch_database_attribute(_, Schema, TableName, SourceColumnName, ColumnType, _, _, _)
921 922 |
923 type_constraint(QueryId, Source, Type, ColumnType).
924
925define_type_from_uncorrelated_table_with_explicit_reference @ 926 query_table(QueryId, uncorrelated(TableName), _)
927 \
928 type_constraint(QueryId, Source, Type, typeof(identifier(_, TableName), SourceColumnName))
929 <=>
930 default_schema(Schema),
931 fetch_database_attribute(_, Schema, TableName, SourceColumnName, ColumnType, _, _, _)
932 |
933 type_constraint(QueryId, Source, Type, ColumnType).
934
935define_type_from_uncorrelated_table @
936 query_table(QueryId, uncorrelated(TableName), _)
937 \
938 type_constraint(QueryId, Source, Type, typeof(X, SourceColumnName))
939 <=>
940 X \= identifier(_,_),
941 942 default_schema(Schema),
943 fetch_database_attribute(_, Schema, TableName, SourceColumnName, ColumnType, _, _, _)
944 |
945 type_constraint(QueryId, Source, Type, ColumnType).
946
947
948crush_xml_subquery_into_scalar @
949 query_is_xml(SubQueryId),
950 subquery(QueryId, SubQueryId)
951 \
952 type_constraint(QueryId, Source, Type, scalar([merged(_, _, _Subtype)]))
953 <=>
954 sql_explain(crush_xml),
955 type_constraint(QueryId, Source, Type, native_type(nvarchar(max))).
956
957
958crush_subquery_into_scalar @
959 type_constraint(QueryId, Source, Type, scalar([merged(_, _, Subtype)]))
960 <=>
961 sql_explain(crush_subquery),
962 type_constraint(QueryId, Source, Type, Subtype).
963
964concatenate_char @
965 type_merge_hint(Type, Hint),
966 type_constraint(QueryId, Source1, Type, native_type(varchar(N))),
967 type_constraint(QueryId, Source2, Type, native_type(varchar(M)))
968 <=>
969 Hint == add ; Hint == concatenate
970 |
971 ( N == max ->
972 Z = max
973 ; M == max ->
974 Z = max
975 ; otherwise ->
976 Z is min(N+M, 8000)
977 ),
978 sql_explain(concatenate_char),
979 merge_sources(Source1, Source2, Source),
980 type_constraint(QueryId, Source, Type, native_type(varchar(Z))),
981 type_constraint_ready(QueryId, Type).
982
983concatenate_nchar_and_varchar @
984 type_merge_hint(Type, Hint),
985 type_constraint(QueryId, Source1, Type, native_type(nvarchar(N))),
986 type_constraint(QueryId, Source2, Type, native_type(varchar(M)))
987 <=>
988 Hint == add ; Hint == concatenate
989 |
990 ( N == max ->
991 Z = max
992 ; M == max ->
993 Z = max
994 ; otherwise->
995 Z is min(N+M, 8000)
996 ),
997 sql_explain(concatenate_nchar_and_varchar),
998 merge_sources(Source1, Source2, Source),
999 type_constraint(QueryId, Source, Type, native_type(nvarchar(Z))),
1000 type_constraint_ready(QueryId, Type).
1001
1002concatenate_nchar_and_nchar @
1003 type_merge_hint(Type, Hint),
1004 type_constraint(QueryId, Source1, Type, native_type(nvarchar(N))),
1005 type_constraint(QueryId, Source2, Type, native_type(nvarchar(M)))
1006 <=>
1007 Hint == add ; Hint == concatenate
1008 |
1009 ( N == max ->
1010 Z = max
1011 ; M == max ->
1012 Z = max
1013 ; otherwise->
1014 Z is min(N+M, 8000)
1015 ),
1016 sql_explain(concatenate_nchar_and_nchar),
1017 merge_sources(Source1, Source2, Source),
1018 type_constraint(QueryId, Source, Type, native_type(nvarchar(Z))),
1019 type_constraint_ready(QueryId, Type).
1020
1021
1022merge_sized_chars @
1023 type_constraint(QueryId, _, Type, native_type(varchar(N)))
1024 \
1025 type_merge_hint(Type, sized_varchar),
1026 type_constraint(QueryId, _, Type, native_type(varchar(M)))
1027 <=>
1028 ( integer(N), integer(M), N < M )
1029 |
1030 sql_explain(merge_sized_chars),
1031 type_constraint_ready(QueryId, Type).
1032
1033union_chars @
1034 type_constraint(QueryId, _, Type, native_type(varchar(N)))
1035 \
1036 type_merge_hint(Type, Hint),
1037 type_constraint(QueryId, _, Type, native_type(varchar(M)))
1038 <=>
1039 Hint \== concatenate,
1040 ( N == max
1041 ; M == max
1042 ; N >= M
1043 )
1044 |
1045 sql_explain(union_chars(N, M)),
1046 type_constraint_ready(QueryId, Type).
1047
1048union_nchars @
1049 type_constraint(QueryId, _, Type, native_type(nvarchar(N)))
1050 \
1051 type_merge_hint(Type, Hint),
1052 type_constraint(QueryId, _, Type, native_type(nvarchar(M)))
1053 <=>
1054 Hint \== concatenate,
1055 ( N == max
1056 ; M == max
1057 ; N >= M
1058 )
1059 |
1060 sql_explain(union_nchars),
1061 type_constraint_ready(QueryId, Type).
1062
1063union_nchar_and_varchar @
1064 type_merge_hint(Type, Hint),
1065 type_constraint(QueryId, Source1, Type, native_type(nvarchar(N))),
1066 type_constraint(QueryId, Source2, Type, native_type(varchar(M)))
1067 <=>
1068 Hint \== concatenate
1069 |
1070 ( N == max->
1071 Z = max
1072 ; M == max->
1073 Z = max
1074 ; otherwise->
1075 Z is max(N, M)
1076 ),
1077 sql_explain(union_nchar_and_varchar),
1078 merge_sources(Source1, Source2, Source),
1079 type_constraint(QueryId, Source, Type, native_type(nvarchar(Z))),
1080 type_constraint_ready(QueryId, Type).
1081
1082
1083
1084expand_precision_integer_to_decimal @ 1085 type_constraint(QueryId, Source1, Type, native_type(decimal(_, _)))
1086 \
1087 type_constraint(QueryId, Source2, Type, native_type(int(N)))
1088 <=>
1089 sql_explain(precision_integer_to_decimal(N,0)),
1090 merge_sources(Source1, Source2, Source),
1091 type_constraint(QueryId, Source, Type, native_type(decimal(N, 0))).
1092
1093expand_precision_integer_to_general_integer @
1094 type_constraint(QueryId, _, Type, native_type(int))
1095 \
1096 type_merge_hint(Type, _),
1097 type_constraint(QueryId, _, Type, native_type(int(_)))
1098 <=>
1099 sql_explain(precision_integer_to_int),
1100 type_constraint_ready(QueryId, Type).
1101
1102
1103expand_integer_to_decimal @
1104 type_merge_hint(Type, union),
1105 type_constraint(QueryId, Source1, Type, native_type(decimal(_, _)))
1106 \
1107 type_constraint(QueryId, Source2, Type, native_type(int))
1108 <=>
1109 sql_explain(integer_to_decimal_for_union),
1110 merge_sources(Source1, Source2, Source),
1111 type_constraint(QueryId, Source, Type, native_type(decimal(10,0))).
1112
1113expand_tinyint_to_int @
1114 type_constraint(QueryId, _, Type, native_type(int))
1115 \
1116 type_merge_hint(Type, _),
1117 type_constraint(QueryId, _, Type, native_type(tinyint))
1118 <=>
1119 sql_explain(tinyint_to_int),
1120 type_constraint_ready(QueryId, Type).
1121
1122expand_tinyint_to_precision_int @
1123 type_constraint(QueryId, _, Type, native_type(int(_)))
1124 \
1125 type_merge_hint(Type, _),
1126 type_constraint(QueryId, _, Type, native_type(tinyint))
1127 <=>
1128 sql_explain(tinyint_to_precision_integer),
1129 type_constraint_ready(QueryId, Type).
1130
1131
1132expand_int_to_float @
1133 type_constraint(QueryId, _, Type, native_type(float(_)))
1134 \
1135 type_merge_hint(Type, _),
1136 type_constraint(QueryId, _, Type, native_type(int))
1137 <=>
1138 sql_explain(int_to_float),
1139 type_constraint_ready(QueryId, Type).
1140
1142quirk_tinyint_and_varchar_is_tinyint @
1143 type_constraint(QueryId, _, Type, native_type(tinyint))
1144 \
1145 type_merge_hint(Type, _),
1146 type_constraint(QueryId, _, Type, native_type(varchar(_)))
1147 <=>
1148 sql_explain(tinyint_and_varchar),
1149 type_constraint_ready(QueryId, Type).
1150
1151max_varchars @
1152 type_constraint(QueryId, _, Type, native_type(varchar(A)))
1153 \
1154 type_merge_hint(Type, max),
1155 type_constraint(QueryId, _, Type, native_type(varchar(B)))
1156 <=>
1157 integer(A), integer(B), A >= B
1158 |
1159 sql_explain(max_varchars),
1160 type_constraint_ready(QueryId, Type).
1161
1162max_nvarchar_with_varchar @
1163 type_merge_hint(Type, max),
1164 type_constraint(QueryId, Source1, Type, native_type(nvarchar(A))),
1165 type_constraint(QueryId, Source2, Type, native_type(varchar(B)))
1166 <=>
1167 ( ( A == max ; B == max)->
1168 C = max
1169 ; otherwise->
1170 C is max(A, B)
1171 ),
1172 sql_explain(max_vvarchar_with_varchar),
1173 merge_sources(Source1, Source2, Source),
1174 type_constraint(QueryId, Source, Type, native_type(nvarchar(C))),
1175 type_constraint_ready(QueryId, Type).
1176
1177
1178str_expression_with_int @
1179 type_merge_hint(Type, str),
1180 type_constraint(QueryId, Source1, Type, native_type(int)),
1181 type_constraint(QueryId, Source2, Type, native_type(varchar(A)))
1182 <=>
1183 ( A == max ->
1184 B = max
1185 ; otherwise ->
1186 B is max(A, 10)
1187 ),
1188 sql_explain(str_expression_with_int),
1189 merge_sources(Source1, Source2, Source),
1190 type_constraint(QueryId, Source, Type, native_type(varchar(B))),
1191 type_constraint_ready(QueryId, Type).
1192
1194quirk_int_and_varchar_is_int @
1195 type_constraint(QueryId, Source1, Type, native_type(int))
1196 \
1197 type_merge_hint(Type, _),
1198 type_constraint(QueryId, Source2, Type, native_type(varchar(_)))
1199 <=>
1200 sql_explain(int_and_varchar),
1201 type_mismatch(Source1, Source2, int, varchar),
1202 type_constraint_ready(QueryId, Type).
1203
1204quirk_int_and_varchar_is_int @
1205 type_constraint(QueryId, Source1, Type, native_type(int(_)))
1206 \
1207 type_merge_hint(Type, _),
1208 type_constraint(QueryId, Source2, Type, native_type(varchar(_)))
1209 <=>
1210 sql_explain(int_and_varchar),
1211 type_mismatch(Source1, Source2, int, varchar),
1212 type_constraint_ready(QueryId, Type).
1213
1214
1216quirk_datetime_and_int_is_int @
1217 type_constraint(QueryId, _, Type, native_type(datetime))
1218 \
1219 type_merge_hint(Type, _),
1220 type_constraint(QueryId, _, Type, native_type(int))
1221 <=>
1222 sql_explain(datetime_and_int),
1223 type_constraint_ready(QueryId, Type).
1224
1226quirk_datetime_and_precision_int_is_precision_int @
1227 type_constraint(QueryId, _, Type, native_type(datetime))
1228 \
1229 type_merge_hint(Type, _),
1230 type_constraint(QueryId, _, Type, native_type(int(_)))
1231 <=>
1232 sql_explain(datetime_and_precision_int),
1233 type_constraint_ready(QueryId, Type).
1234
1235
1236integer_addition @
1237 type_constraint(QueryId, _, Type, native_type(int))
1238 \
1239 type_merge_hint(Type, Hint),
1240 type_constraint(QueryId, _, Type, native_type(int))
1241 <=>
1242 memberchk(Hint, [add, subtract, concatenate])
1243 |
1244 sql_explain(integer_addition),
1245 type_constraint_ready(QueryId, Type).
1246
1247integer_multiplication_requires_promotion @
1248 type_merge_hint(Type, Hint)
1249 \
1250 type_constraint(QueryId, Source, Type, native_type(int))
1251 <=>
1252 memberchk(Hint, [multiply, divide(_)])
1253 |
1254 sql_explain(promote_int_for_multiplication),
1255 type_constraint(QueryId, Source, Type, native_type(decimal(10,0))).
1256
1257
1258integer_and_decimal_arithmetic @
1259 type_merge_hint(Type, Hint),
1260 type_constraint(QueryId, Source1, Type, native_type(decimal(_, _)))
1261 \
1262 type_constraint(QueryId, Source2, Type, native_type(int))
1263 <=>
1264 Hint \== union
1265 |
1266 sql_explain(promote_int_to_decimal_for_arithmetic(Hint)),
1267 merge_sources(Source1, Source2, Source),
1268 type_constraint(QueryId, Source, Type, native_type(decimal(10,0))).
1269
1270
1271expand_type_scope_decimal_with_hint @
1272 type_merge_hint(Type, Hint),
1273 type_constraint(QueryId, Source1, Type, native_type(decimal(P1, S1))),
1274 type_constraint(QueryId, Source2, Type, native_type(decimal(P2, S2)))
1275 <=>
1276 ( Hint == multiply->
1277 P is P1 + P2 + 1,
1278 S is S1 + S2
1279 ; ( Hint == add ; Hint == concatenate) -> 1280 P is max(S1, S2) + max(P1-S1, P2-S2) + 1,
1281 S is max(S1, S2)
1282 ; Hint == subtract ->
1283 P is max(S1, S2) + max(P1-S1, P2-S2) + 1,
1284 S is max(S1, S2)
1285 ; Hint = divide(DA)->
1286 ( DA = node(Divisor, _, _, _, _) ->
1287 true
1288 ; otherwise->
1289 Divisor = DA
1290 ),
1291 1292 1293 ( Divisor = domain(D) ->
1294 fetch_domain_data_type(D, V)
1295 ; Divisor = native_type(V)->
1296 true
1297 ; otherwise->
1298 throw(bad_divisor(Divisor))
1299 ),
1300 ( ( ( V = int(P1), S1 == 0) 1301 ;
1302 V == decimal(P1, S1))->
1303
1304 1305 P is P2 - S2 + S1 + max(6, S2 + P1 + 1),
1306 S is max(6, S2 + P1 + 1)
1307 ; otherwise->
1308 1309 P is P1 - S1 + S2 + max(6, S1 + P2 + 1),
1310 S is max(6, S1 + P2 + 1)
1311 )
1312 ; Hint == union->
1313 P is max(S1, S2) + max(P1-S1, P2-S2),
1314 S is max(S1, S2)
1315 ; otherwise->
1316 throw(unhandled_scope(Hint))
1317 ),
1318 ( P > 38 ->
1319 Px = 38,
1320 1321 1322 1323 ( memberchk(Hint, [add, concatenate, subtract])->
1324 Sx is max(0, S - (P-39))
1325 ; Hint == union->
1326 Sx is max(0, S - (P-38))
1327 ; max(0, S-(P-38)) < 6->
1328 Sx is min(S, 6)
1329 ; otherwise->
1330 Sx is max(0, S - (P-38))
1331 )
1332 ; otherwise->
1333 Px = P,
1334 Sx = S
1335 ),
1336 sql_explain(decimal_arithmetic(Hint, Px, Sx)),
1337 merge_sources(Source1, Source2, Source),
1338 type_constraint(QueryId, Source, Type, native_type(decimal(Px, Sx))),
1339 type_constraint_ready(QueryId, Type).
1340
1341resolve_types @
1342 resolve_types(QueryId)
1343 <=>
1344 commit(QueryId).
1345
1346resolve_unions @
1347 commit(QueryId)
1348 \
1349 union_type(QueryId, L, R, T)
1350 <=>
1351 is_list(L),
1352 is_list(R)
1353 |
1354 ( resolve_union_type(QueryId, L, R, T)->
1355 true
1356 ; otherwise->
1357 format(atom(Message), 'Could not determine the type of the union of ~w and ~w', [L, R]),
1358 throw(cql_error(failed_to_resolve_union, Message))
1359 ).
1360
1361resolve_derived_tables @
1362 commit(QueryId),
1363 derived_table(QueryId, Table, Constraint)
1364 <=>
1365 is_list(Constraint)
1366 |
1367 create_derived_table(QueryId, Table, Constraint),
1368 commit(QueryId).
1369
1370union_of_type_decimal_domains_is_not_a_domain @
1371 commit(QueryId), 1372 type_merge_hint(Type, union),
1373 type_constraint(QueryId, Source1, Type, domain(D1)),
1374 type_constraint(QueryId, Source2, Type, domain(D2))
1375 <=>
1376 fetch_domain_data_type(D1, decimal(A1, A2)),
1377 fetch_domain_data_type(D2, decimal(B1, B2))
1378 |
1379 sql_explain(union_domains),
1380 most_general_type(QueryId, Source1, Source2, decimal(A1, A2), decimal(B1, B2), union, Type),
1381 commit(QueryId).
1382
1383merge_domains @
1384 commit(QueryId), 1385 type_merge_hint(Type, Hint),
1386 type_constraint(QueryId, Source1, Type, domain(D1)),
1387 type_constraint(QueryId, Source2, Type, domain(D2))
1388 <=>
1389 fetch_domain_data_type(D1, T1),
1390 fetch_domain_data_type(D2, T2)
1391 |
1392 ( T1 = decimal(_, _),
1393 T2 = decimal(_, _)->
1394 most_general_type(QueryId, Source1, Source2, T1, T2, Hint, Type)
1395 ; T1 = datetime, T2 = datetime, memberchk(Hint, [add, subtract, concatenate])->
1396 type_constraint(QueryId, Source1, Type, native_type(datetime)),
1397 type_constraint_ready(QueryId, Type)
1398 ; D1 == D2, Hint \== concatenate->
1399 type_constraint(QueryId, Source1, Type, domain(D1)),
1400 type_constraint_ready(QueryId, Type)
1401 ; otherwise->
1402 most_general_type(QueryId, Source1, Source1, T1, T2, Hint, Type)
1403 ),
1404 sql_explain(join_domains_for(Hint, D1, D2, Type)),
1405 commit(QueryId).
1406
1407merge_domain_to_native @
1408 commit(QueryId), 1409 type_merge_hint(Type, Hint),
1410 type_constraint(QueryId, Source1, Type, domain(D)),
1411 type_constraint(QueryId, Source2, Type, native_type(NT))
1412 <=>
1413 fetch_domain_data_type(D, T)
1414 |
1415 sql_explain(join_domain_to_native),
1416 most_general_type(QueryId, Source1, Source2, T, NT, Hint, Type),
1417 commit(QueryId).
1418
1419drop_nulltype_in_favour_of_domain @
1420 1421 type_merge_hint(Type, _Anything),
1422 type_constraint(QueryId, Source1, Type, domain(D)),
1423 type_constraint(QueryId, Source2, Type, {nulltype})
1424 <=>
1425 sql_explain(drop_nulltype_for_domain),
1426 fetch_domain_data_type(D, T),
1427 merge_sources(Source1, Source2, Source),
1428 type_constraint(QueryId, Source, Type, native_type(T)),
1429 type_constraint_ready(QueryId, Type).
1430
1431drop_nulltype_in_favour_of_native_type @
1432 type_constraint(QueryId, _, Type, native_type(T))
1433 \
1434 type_merge_hint(Type, Hint),
1435 type_constraint(QueryId, _, Type, {nulltype})
1436 <=>
1437 sql_explain(drop_nulltype_for_native(T, Hint)),
1438 type_constraint_ready(QueryId, Type).
1439
1440
1451drop_nulltype_in_favour_of_another_nulltype @
1452 type_constraint(QueryId, _, Type, {nulltype})
1453 \
1454 type_merge_hint(Type, Hint),
1455 type_constraint(QueryId, _, Type, {nulltype})
1456 <=>
1457 ( Hint == union ->
1458 ( prolog_load_context(file, _Filename)->
1459 true
1460 1461 ; otherwise->
1462 true
1463 )
1464 ; otherwise->
1465 true
1466 ),
1467 sql_explain(drop_nulltype_for_nulltype(Hint)),
1468 type_constraint_ready(QueryId, Type).
1469
1470force_type_not_domain @
1471 1472 force_type_not_domain(Type),
1473 type_constraint(QueryId, Source, Type, domain(D))
1474 <=>
1475 fetch_domain_data_type(D, decimal(P, S))
1476 |
1477 sql_explain(forcing_decimal_not_domain(D)),
1478 type_constraint(QueryId, Source, Type, native_type(decimal(P, S))).
1479
1480force_type_not_domain @
1481 1482 force_type_not_domain(Type),
1483 type_constraint(QueryId, Source, Type, domain(D))
1484 <=>
1485 fetch_domain_data_type(D, varchar(L))
1486 |
1487 sql_explain(forcing_varchar_not_domain(D)),
1488 type_constraint(QueryId, Source, Type, native_type(varchar(L))).
1489
1490force_type_not_domain @
1491 force_type_not_domain(Type),
1492 type_constraint(QueryId, Source, Type, domain(D))
1493 <=>
1494 fetch_domain_data_type(D, datetime)
1495 |
1496 sql_explain(forcing_datetime_not_domain(D)),
1497 type_constraint(QueryId, Source, Type, native_type(datetime)).
1498
1499
1500rounded_int_is_decimal @ 1501 type_merge_hint(Type, round),
1502 type_constraint(QueryId, Source, Type, native_type(int))
1503 <=>
1504 sql_explain(rounded_int_is_decimal),
1505 type_constraint(QueryId, Source, Type, native_type(decimal(10,0))).
1506
1507rounded_decimal_has_no_scale @
1508 type_merge_hint(Type, round),
1509 type_constraint(QueryId, Source, Type, native_type(decimal(P, _)))
1510 <=>
1511 sql_explain(rounded_decimal_has_no_scale),
1512 type_constraint(QueryId, Source, Type, native_type(decimal(P,0))).
1513
1514
1515force_domain_type_to_sum @
1516 1517 type_merge_hint(Type, sum),
1518 type_constraint(QueryId, Source, Type, domain(D))
1519 <=>
1520 fetch_domain_data_type(D, decimal(_, S))
1521 |
1522 sql_explain(forcing_domain_to_sum(D)),
1523 type_constraint(QueryId, Source, Type, native_type(decimal(38, S))).
1524
1525force_domain_type_to_avg @
1526 1527 type_merge_hint(Type, avg),
1528 type_constraint(QueryId, Source, Type, domain(D))
1529 <=>
1530 sql_explain(forcing_domain_to_avg(D)),
1531 type_constraint(QueryId, Source, Type, native_type(decimal(38, 6))).
1532
1533force_native_type_to_sum @
1534 1535 type_merge_hint(Type, sum),
1536 type_constraint(QueryId, Source, Type, native_type(decimal(_, S)))
1537 <=>
1538 sql_explain(forcing_native_to_sum),
1539 type_constraint(QueryId, Source, Type, native_type(decimal(38, S))).
1540
1541force_native_type_to_avg @
1542 1543 type_merge_hint(Type, avg),
1544 type_constraint(QueryId, Source, Type, native_type(decimal(_, _)))
1545 <=>
1546 sql_explain(forcing_native_to_avg),
1547 type_constraint(QueryId, Source, Type, native_type(decimal(38, 6))).
1548
1549union_precision_ints @
1550 type_merge_hint(Type, union),
1551 type_constraint(QueryId, Source1, Type, native_type(int(_))),
1552 type_constraint(QueryId, Source2, Type, native_type(int(_)))
1553 <=>
1554 sql_explain(union_precision_ints),
1555 merge_sources(Source1, Source2, Source),
1556 type_constraint(QueryId, Source, Type, native_type(int)),
1557 type_constraint_ready(QueryId, Type).
1558
1559union_identical_natives @
1560 type_constraint(QueryId, _, Type, native_type(T))
1561 \
1562 type_merge_hint(Type, union),
1563 type_constraint(QueryId, _, Type, native_type(T))
1564 <=>
1565 sql_explain(union_identical_natives(T)),
1566 type_constraint_ready(QueryId, Type).
1567
1568merge_datetime_and_int @
1569 type_merge_hint(Type, _Hint),
1570 type_constraint(QueryId, Source1, Type, native_type(datetime)),
1571 type_constraint(QueryId, Source2, Type, native_type(decimal(_,_)))
1572 <=>
1573 sql_explain(operation_with_datetime_and_decimal),
1574 merge_sources(Source1, Source2, Source),
1575 type_constraint(QueryId, Source, Type, native_type(datetime)),
1576 type_constraint_ready(QueryId, Type).
1577
1578union_of_datetime_and_date_is_datetime @
1579 type_merge_hint(Type, union),
1580 type_constraint(QueryId, Source, Type, native_type(datetime))
1581 \
1582 type_constraint(QueryId, Source, Type, native_type(date))
1583 <=>
1584 sql_explain(union_of_datetime_and_date),
1585 type_constraint_ready(QueryId, Type).
1586
1587
1588accept_domain @
1589 type_constraint(QueryId, _, Type, domain(Domain)),
1590 type_constraint_ready(QueryId, Type)
1591 <=>
1592 sql_explain(accepting(domain(Domain), Type)),
1593 Type = domain(Domain).
1594
1595accept_native_type @
1596 type_constraint(QueryId, _, Type, native_type(Native)),
1597 type_constraint_ready(QueryId, Type)
1598 <=>
1599 sql_explain(accepting(native_type(Native), Type)),
1600 Type = native_type(Native).
1601
1602accept_nulltype @
1603 type_constraint(QueryId, _, Type, {nulltype}),
1604 type_constraint_ready(QueryId, Type)
1605 <=>
1606 sql_explain(accepting_nulltype(Type)),
1607 Type = {nulltype}.
1608
1609
1610find_column_types @
1611 query_table(QueryId, _, identifier(_, TableName)),
1612 find_all_column_types(QueryId, Source, Tail)
1613 <=>
1614 default_schema(Schema),
1615 findall(merged(ColumnName, Source, Domain),
1616 fetch_database_attribute(_, Schema, TableName, ColumnName, Domain, _, _, _),
1617 Columns),
1618 create_column_constraints(QueryId, Source, Columns, Tail, NewTail),
1619 find_all_column_types(QueryId, Source, NewTail).
1620
1621find_column_types @
1622 derived_query_column(QueryId, _, Column, ColumnType),
1623 find_all_column_types(QueryId, Source, Tail)
1624 <=>
1625 Tail = [merged(Column, Source, ColumnType)|NewTail],
1626 find_all_column_types(QueryId, Source, NewTail).
1627
1628share_commit @
1629 commit(Parent),
1630 subquery(Parent, Child)
1631 ==>
1632 commit(Child).
1633
1634commit_peers @
1635 commit(Qid),
1636 peer_query(Qid, Sibling)
1637 ==>
1638 commit(Sibling).
1639
1640
1641share_table @
1642 subquery(Parent, Child),
1643 query_table(Parent, A, B)
1644 ==>
1645 query_table(Child, A, B).
1646
1652
1653finished_finding @
1654 commit(QueryId)
1655 \
1656 find_all_column_types(QueryId, _, Tail)
1657 <=>
1658 Tail = [].
1659
1669
1670frozen_reverse @
1671 frozen_reverse(_, A, B)
1672 <=>
1673 is_list(A)
1674 |
1675 A = B.
1677
1678cleanup @ cleanup(QueryId) \ frozen_reverse(QueryId, _, _) <=> true.
1679cleanup @ cleanup(QueryId) \ type_constraint(QueryId, _, _, _) <=> true. 1680cleanup @ cleanup(_QueryId) \ type_constraint_ready(_, _) <=> true.
1681cleanup @ cleanup(_QueryId) \ type_merge_hint(_, _) <=> true.
1682cleanup @ cleanup(QueryId) \ query_table(QueryId, _, _) <=> true.
1683cleanup @ cleanup(QueryId) \ derived_query_column(QueryId, _, _, _) <=> true.
1684cleanup @ cleanup(QueryId) \ subquery(QueryId, SubQueryId) <=> cleanup(SubQueryId).
1685cleanup @ cleanup(QueryId) \ peer_query(QueryId, PeerQueryId) <=> cleanup(PeerQueryId).
1686cleanup @ cleanup(QueryId) \ query_is_xml(QueryId) <=> true.
1687cleanup @ cleanup(QueryId) \ commit(QueryId) <=> true.
1688cleanup @ cleanup(QueryId) \ find_all_column_types(QueryId, _, _) <=> true.
1689cleanup @ cleanup(QueryId) \ subquery(SubQueryId, QueryId) <=> cleanup(SubQueryId).
1691cleanup @ cleanup(_) <=> true.
1692
1693create_column_constraints(_QueryId, _Source, [], NewTail, NewTail):- !.
1694create_column_constraints(QueryId, Source, [merged(Name, Source, Domain)|Columns], [merged(Name, Source, Type)|T], NewTail):-
1695 type_constraint(QueryId, Source, Type, Domain),
1696 type_constraint_ready(QueryId, Type),
1697 create_column_constraints(QueryId, Source, Columns, T, NewTail).
1698
1699
1700resolve_union_type(_QueryId, [], [], []):- !.
1701resolve_union_type(_QueryId, A, [], []):- throw(union_mismatch(left(A))).
1702resolve_union_type(_QueryId, [], A, []):- throw(union_mismatch(right(A))).
1703resolve_union_type(QueryId, [merged(NameA, SourceA, TypeA)|As], [merged(NameB, SourceB, TypeB)|Bs], [merged(Name, SourceA, C)|Cs]):-
1704 1705 1706 1707 ( nonvar(TypeA),
1708 TypeA = domain(X),
1709 nonvar(TypeB),
1710 TypeB = domain(X),
1711 fetch_domain_data_type(X, decimal(P, S))->
1712 C = native_type(decimal(P,S))
1713 ; otherwise->
1714 type_merge_hint(C, union),
1715 type_constraint(QueryId, SourceA, C, TypeA),
1716 type_constraint(QueryId, SourceB, C, TypeB)
1717 ),
1718 ( NameA == {no_alias} ->
1719 name_from_identifier(NameB, Name)
1720 ; otherwise->
1721 name_from_identifier(NameA, Name)
1722 ),
1723 resolve_union_type(QueryId, As, Bs, Cs).
1724
1725
1726name_from_identifier(literal(NameMC, _), Name):- !,
1727 downcase_atom(NameMC, Name).
1728name_from_identifier({no_alias}, {no_alias}):- !.
1729name_from_identifier(Identifier, Name):-
1730 downcase_atom(Identifier, Name).
1731
1732
1733
1734
1735check_types(_, _).
1736most_general_type(QueryId, S1, S2, A, B, Op, C):-
1737 type_merge_hint(C, Op),
1738 ( var(A)->
1739 type_constraint(QueryId, S1, C, A)
1740 ; otherwise->
1741 strip_sql_comments(A, AA),
1742 ( AA = native_type(AAA)->
1743 type_constraint(QueryId, S1, C, native_type(AAA))
1744 ; AA = domain(AAA)->
1745 type_constraint(QueryId, S1, C, domain(AAA))
1746 ; AA == {nulltype}->
1747 type_constraint(QueryId, S1, C, {nulltype})
1748 ; otherwise->
1749 type_constraint(QueryId, S1, C, native_type(AA))
1750 )
1751 ),
1752 ( var(B)->
1753 type_constraint(QueryId, S2, C, B)
1754 ; otherwise->
1755 strip_sql_comments(B, BB),
1756 ( BB = native_type(BBB)->
1757 type_constraint(QueryId, S2, C, native_type(BBB))
1758 ; BB = domain(BBB)->
1759 type_constraint(QueryId, S2, C, domain(BBB))
1760 ; BB == {nulltype}->
1761 type_constraint(QueryId, S2, C, {nulltype})
1762 ; otherwise->
1763 type_constraint(QueryId, S2, C, native_type(BB))
1764 )
1765 ).
1766
1768coalesce_type(QueryId, [A, B], [S1, S2], T):- !,
1769 most_general_type(QueryId, S1, S2, A, B, union, T).
1770coalesce_type(QueryId, [A], [S1], T):- !,
1771 type_constraint(QueryId, S1, T, A),
1772 type_constraint_ready(QueryId, T).
1773coalesce_type(QueryId, [A, B|Xs], [S1, S2|Ss], T):-
1774 most_general_type(QueryId, S1, S2, A, B, union, AB),
1775 coalesce_type(QueryId, Xs, Ss, XT),
1776 most_general_type(QueryId, S2, S2, AB, XT, union, T).
1777
1778concatenate_type(QueryId, S1, S2, A, B, C):-
1779 type_merge_hint(C, concatenate),
1780 type_constraint(QueryId, S1, C, A),
1781 type_constraint(QueryId, S2, C, B).
1782
1783
1784merge_types(all, _, Types, Types):- !.
1785merge_types([], [], [], []):- !.
1786merge_types([derived_column(From, Alias)|As], [S|Ss], [B|Bs], [merged(Name, S, B)|Cs]):-
1787 ( Alias == {no_alias},
1788 From = column(_Qualifier, Name)->
1789 true
1790 ; otherwise->
1791 name_from_identifier(Alias, Name)
1792 ),
1793 merge_types(As, Ss, Bs, Cs).
1794
1795
1796determine_tables(_, Var):- var(Var), !, throw(var).
1797determine_tables(_, []):- !.
1798determine_tables(QueryId, [A|B]):- !,
1799 determine_tables(QueryId, A),
1800 determine_tables(QueryId, B).
1801
1802determine_tables(QueryId, join(LHS, RHS)):- !,
1803 determine_tables(QueryId, LHS),
1804 determine_tables(QueryId, RHS).
1805determine_tables(QueryId, correlated_table(table(Identifier), {no_correlation})):- !,
1806 Identifier = identifier(_, TableName), !,
1807 query_table(QueryId, uncorrelated(TableName), Identifier).
1808determine_tables(QueryId, correlated_table(table(Identifier), correlation(Correlation, _))):- !,
1809 query_table(QueryId, Correlation, Identifier).
1810determine_tables(QueryId, qualified_join(_Type, RHS, _On)):- !,
1811 determine_tables(QueryId, RHS).
1812determine_tables(QueryId, cross_join(RHS)):- !,
1813 determine_tables(QueryId, RHS).
1814determine_tables(QueryId, derived_table(_Derivation, correlation(DerivedTableName, _), T)):- !,
1815 derived_table(QueryId, DerivedTableName, T).
1816
1817determine_tables(_, X):- throw(determine_tables(X)).
1818
1819
1820create_derived_table(_QueryId, _DerivedTableName, []):- !.
1821create_derived_table(QueryId, DerivedTableName, [merged(Name, _, Type)|Columns]):- !,
1822 derived_query_column(QueryId, DerivedTableName, Name, Type),
1823 create_derived_table(QueryId, DerivedTableName, Columns).
1824
1826fetch_domain_data_type(identifier(_, Domain), Type):-
1827 !,
1828 fetch_domain_data_type(Domain, Type).
1829fetch_domain_data_type(Domain, Type):-
1830 domain_database_data_type(Domain, Type).
1831
1832fetch_database_attribute(_, Schema, TableName, _, _, _, _, _):-
1833 \+system_table(TableName, _, _),
1834 \+database_attribute(_, Schema, TableName, _, _, _, _, _),
1835 !,
1836 format(atom(Message), 'View references entity ~w which does not exist', [TableName]),
1837 throw(cql_error(no_such_entity, Message)).
1838
1839fetch_database_attribute(_, Schema, TableName, ColumnName, Domain, _, _, _):-
1840 system_table(TableName, ColumnName, Domain)
1841 ;
1842 database_attribute(_, Schema, TableName, ColumnName, Domain, _, _, _).
1843
1844
1845system_table(sysobjects, name, native_type(nvarchar(128))).
1846system_table(sysobjects, name, native_type(nvarchar(128))).
1847system_table(sysobjects, xtype, native_type(char(2))).
1848system_table(sysobjects, xtype, native_type(nvarchar(128))).
1849system_table(sysobjects, id, native_type(int)).
1850system_table(sysobjects, uid, native_type(smallint)).
1851system_table(sysobjects, parent_obj, native_type(int)).
1852system_table(syscolumns, name, native_type(nvarchar(128))).
1853system_table(syscolumns, colid, native_type(smallint)).
1854system_table(syscolumns, id, native_type(int)).
1855system_table(sysconstraints, colid, native_type(smallint)).
1856system_table(sysconstraints, constid, native_type(int)).
1857system_table(syscomments, id, native_type(int)).
1858system_table(syscomments, text, native_type(nvarchar(4000))).
1859system_table(syscomments, colid, native_type(smallint)).
1860
1861system_table(table_constraints, constraint_catalog, native_type(nvarchar(128))).
1862system_table(table_constraints, constraint_schema, native_type(nvarchar(128))).
1863system_table(table_constraints, constraint_name, native_type(nvarchar(128))).
1864system_table(table_constraints, constraint_type, native_type(varchar(11))).
1865system_table(table_constraints, table_catalog, native_type(nvarchar(128))).
1866system_table(table_constraints, table_schema, native_type(nvarchar(128))).
1867system_table(table_constraints, table_name , native_type(nvarchar(128))).
1868
1869system_table(key_column_usage, constraint_name, native_type(nvarchar(128))).
1870system_table(key_column_usage, table_catalog, native_type(nvarchar(128))).
1871system_table(key_column_usage, table_schema, native_type(nvarchar(128))).
1872system_table(key_column_usage, table_name, native_type(nvarchar(128))).
1873system_table(key_column_usage, column_name, native_type(nvarchar(128))).
1874system_table(key_column_usage, ordinal_position, native_type(int)).
1875
1876system_table(referential_constraints, constraint_name, native_type(nvarchar(128))).
1877system_table(referential_constraints, constraint_catalog, native_type(nvarchar(128))).
1878system_table(referential_constraints, constraint_schema, native_type(nvarchar(128))).
1879system_table(referential_constraints, unique_constraint_name, native_type(nvarchar(128))).
1880system_table(referential_constraints, unique_constraint_catalog, native_type(nvarchar(128))).
1881system_table(referential_constraints, unique_constraint_schema, native_type(nvarchar(128))).
1882
1883
1884left_factor_types(Qid, In, T):-
1885 left_factor2(In, Left),
1886 resolve_factored_types(Qid, Left, T).
1887
1888resolve_factored_types(_Qid, Var, Var):- var(Var), !.
1889resolve_factored_types(Qid, node(A, AS, Op, B, BS), T):- !,
1890 most_general_type(Qid, AS, BS, AT, B, Op, T),
1891 resolve_factored_types(Qid, A, AT).
1892resolve_factored_types(_Qid, T, T).
1893
1895left_factor2(A, A):- var(A), !.
1896left_factor2(node(A, AS, Op, B, BS), Y):- !, left_factor_appending2(B, BS, A, AS, Op, Y).
1897left_factor2(A, A).
1898left_factor_appending2(Var, VarS, T, TS, Op, node(T, TS, Op, Var, VarS)):- var(Var), !.
1899left_factor_appending2(node(A, AS, Op1, B, BS), NS, T, TS, Op2, Z):- !, left_factor_appending2(B, BS, node(T, TS, Op2, A, AS), NS, Op1, Z).
1900left_factor_appending2(X, XS, Y, YS, Op, node(Y, YS, Op, X, XS)).
1901
1902
1903
(Var, Var):- var(Var), !. 1905strip_sql_comments(meta(_,_):A, B):- !,
1906 strip_sql_comments(A, B).
1907
1908strip_sql_comments(A, B):-
1909 A =.. [Functor|Args], Args \== [], !,
1910 strip_sql_comments_list(Args, Args2),
1911 B =.. [Functor|Args2].
1912
1913strip_sql_comments(A, A):- !.
1914
([], []):- !.
1916strip_sql_comments_list([A|B], [C|D]):- !, strip_sql_comments(A, C), strip_sql_comments_list(B, D).
1917
1918consolidate_errors(Var):-
1919 var(Var),
1920 throw(instantiation_error(Var)).
1921consolidate_errors(meta(_Comments, ErrorGroup):A):- !,
1922 ( ErrorGroup = {null} ->
1923 true
1924 ; otherwise->
1925 true 1926 ),
1927 consolidate_errors(A).
1928consolidate_errors(A):-
1929 A =.. [_|Args], Args \== [], !,
1930 consolidate_errors_list(Args).
1931consolidate_errors(_):- !.
1932
1933consolidate_errors_list([]):- !.
1934consolidate_errors_list([A|B]):- !, consolidate_errors(A), consolidate_errors_list(B).
1935
1936
1937not_a_builtin_function(DBMS, Function):-
1938 strip_sql_comments(Function, identifier(Schema, Functor)),
1939 \+once(builtin_function(DBMS, Schema, Functor)).
1940
1941builtin_function('Microsoft SQL Server', _, month).
1942builtin_function('Microsoft SQL Server', _, day).
1943builtin_function('Microsoft SQL Server', _, year).
1944builtin_function('Microsoft SQL Server', _, round).
1945builtin_function('Microsoft SQL Server', _, floor).
1946builtin_function('Microsoft SQL Server', _, ceiling).
1947builtin_function('Microsoft SQL Server', _, len).
1948builtin_function('Microsoft SQL Server', _, rtrim).
1949builtin_function('Microsoft SQL Server', _, str).
1950builtin_function('Microsoft SQL Server', _, datename).
1951builtin_function('Microsoft SQL Server', _, getdate).
1952
1953builtin_function('Microsoft SQL Server', _, db_name).
1954builtin_function('Microsoft SQL Server', _, permissions).
1955builtin_function('Microsoft SQL Server', _, user_name).
1956
1957routine_type(Name, Type):-
1958 1959 1960 default_schema(Schema),
1961 dbms(Schema, DBMS),
1962 strip_sql_comments(Name, identifier(_, Identifier)),
1963 ( cql_normalize_name(DBMS, Identifier, NormalizedName),
1964 routine_return_type(Schema, NormalizedName, Type),
1965 Type \== void->
1966 true
1967 ; otherwise->
1968 format(atom(Message), 'Could not determine the type of SQL function ~w', [Identifier]),
1969 throw(cql_error(cannot_determine_function_type, Message))
1970 ).
1971
1972merge_sources(S, S, S):- !.
1973merge_sources(A, B, _):-
1974 format(atom(Message), '~w vs ~w', [A, B]),
1975 throw(cql_error(could_not_merge_sources, Message)).
1976
1977type_mismatch(type_mismatch(Link, Type1, Type2), type_mismatch(Link, Type1, Type2), Type1, Type2):-
1978 1979 1980 flag(sql_error, Link, Link+1),
1981 !.
1982
1984type_mismatch(_, _, _, _):- !.
1985
1988
1989
1990semantic_error(Error, Error, Level):-
1991 1992 1993 1994 !,
1995 format_sql_error(Error, _, Message),
1996 sql_gripe(Level, Message, []).
1997
1998semantic_error(_, _, _)
SQL Parser
This module contains an SQL parser
sql_parse/4
Parsing is invoked with
sql_parse(+Term, -TrailingComments, +Options, +Tokens)
. Notice that all terms are bound when the predicate is called: you must direct the parser where to start. For a view definition, an example invocation might besql_tokens(Tokens, "CREATE VIEW foo AS SELECT bar FROM qux", [])
,sql_parse(view_definition(Definition, Types), TrailingComments, [], Tokens)
. ---++ Comments Because comments can appear literally anywhere in the input text, every parse node has both a syntax element (such as view_definition/2) and a list of comments which preceed the element. This means comments are pushed as far as possible down the syntax tree. Any transformations of the input with the intention that it should be printed out again need to take the comments into account. Any other uses of the parse tree may pass it tostrip_sql_comments(+InTree, -OutTree)
to simply remove them all, leaving the tree with just the syntactic elements.Finally, there may be trailing comments at the end of the input which are not followed by any token. This means they're not absorbed into the parse tree - so that they're not lost, they are returned as a list from sql_parse/4. ---++ Options Current options include:
dbms(+DBMS)
: If omitted, DBMS will be set to 'Microsoft SQL Server'. For the most part only 'Microsoft SQL Server' views are parseable, but it would not be difficult to extend the parser if this was ever required (just search the source fordbms('Microsoft SQL Server')
conditionals)view_name(+Name)
: Passed to gripe/6 so that complaints about view syntax can be associated with a view nameInternally used options include (these should not be passed in under normal circumstances)
query_id(-Qid)
: Used to logically separate distinct parts of the queryParse tree
The parse tree returned can be very complicated. The best documentation for this is probably either the sql_write or the sql_check module, which take the tree as an input and do processing on it. ---++ Type inference Type inference makes the parser take almost 4 times longer, but the resulting information is very useful. It is rarely possible to tell as the input is read what the type of each element is. Where possible, the types are defined (for example, the type of
count(*)
is alwaysnative_type(int)
) but where the type is unknown, a new variable is created and a constraint is made.Type inference is done with CHR, and types are in one of three states: 1 Known, and bound (ie committed) 2 Unknown with one unresolved dependency 3 Unknown with two unresolved dependencies
A dependency here refers to something which would influence the eventual type. Some examples of the slightly more complicated case 2:
scalar(_)
and replaces it with the single element it contains.Some examples of case 3:
Internal Details
Syntax of the grammar
The grammar started out as an EBNF format, and is based roughly on http://savage.net.au/SQL/sql-92.bnf.html {}/1 are escaped Prolog, like in a DCG [...] denote optional clauses | denotes options @foo matches the token foo (case-insensitive matching is employed) #Foo matches the next token with Foo #Foo:Type matches the next token with Foo if it is a literal of type Type
Left factoring types
SQL Server has some very complicated rules for inferring the type of decimal arithmetic (see http://msdn.microsoft.com/en-us/library/ms190476). The crucial, yet sadly missing information from that page deals with overflows. This is half-explained at http://blogs.msdn.com/b/sqlprogrammability/archive/2006/03/29/564110.aspx.
Because we have truncation, the order of operations is crucial: Although (x * y) / z is mathematically equivalent to x * (y / z), the types of the two expressions in SQL Server are actually different due to truncation. The parser is LL, but this means we will always read x * y / z as x * (y / z), whereas SQL Server does the type inference in reverse. This is only a problem for division and multiplication since the handling of addition and subtraction are symmetric, but without a transformation, we will compute the wrong type. After a term/2 is parsed, left_factor_types/3 is called, which translates just the types in the term from LL into LR form.
Uses
Known problems
% It is not practical to determine what + means ahead of time if the source view is MS T-SQL. We would have to guess and backtrack if wrong, and that is horribly inefficient. Instead if we read + in 'Microsoft SQL Server' mode, we should delay determining whether it is really + or actually || until the types of the LHS and RHS are resolved. */