File: cs_util.ml

package info (click to toggle)
galax 1.1-10
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 12,832 kB
  • sloc: ml: 96,603; xml: 26,602; ansic: 4,875; sh: 3,977; makefile: 1,667; java: 1,146
file content (308 lines) | stat: -rw-r--r-- 10,141 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
(***********************************************************************)
(*                                                                     *)
(*                                 GALAX                               *)
(*                              XQuery Engine                          *)
(*                                                                     *)
(*  Copyright 2001-2007.                                               *)
(*  Distributed only by permission.                                    *)
(*                                                                     *)
(***********************************************************************)

(* $Id: cs_util.ml,v 1.38 2007/02/21 21:14:43 simeon Exp $ *)

(* Module: Cs_util
   Description:
     This module contains some auxiliary evaluation functions, notably
     for function calls, type declarations, axis, element and
     attribute construction.
*)

open Format

open Error

(* open Namespace_symbols *)

open Datatypes
open Datatypes_util

open Xquery_ast
open Xquery_algebra_ast
open Xquery_algebra_ast_util
open Xquery_common_ast
open Xquery_algebra_ast_annotation_util

open Physical_xml_value
open Physical_value
open Physical_value_util

open Norm_context
open Typing_context
open Code_selection_context
open Variable_context_manager


(*************)
(* Constants *)
(*************)

(* idiomatic constants that appear in multiple locations *)
let empty_dom_sequence     = (Physical_sequence.materialized_of_list [])
let non_empty_dom_sequence = (Physical_sequence.materialized_of_list ([Item_Atomic Dm_atomic_util.integer_one]))

let empty_sequence     = (DomValue empty_dom_sequence)
let non_empty_sequence = (DomValue non_empty_dom_sequence)

let empty_tuple        = Physical_table.empty_tuple
let empty_tuple_opt    = Some empty_tuple (* Useful in cursor returns *)

(******************)
(* Error messages *)
(******************)

let raise_document_element_singleton () =
  raise (Query (Prototype "document node does not contain a singleton children element"))

let raise_computed_tag_error () =
  raise (Query (Code_Selection "Computed tag not a Qname or string"))

let raise_cast_to_symbol_failure () =
  raise (Query (Code_Selection "Failure in Cs_util.cast_to_symbol"))

let raise_cast_to_bool_failure () =
  raise (Query (Code_Selection "Failure in Cs_util.cast_to_bool"))

let raise_in_forest_compare msg =
  raise (Query(Datamodel("In forest_compare :"^msg)))

let raise_type_error_in_function_arguments fn =
  raise (Query (Type_Error ("Arguments to function '"
				 ^ (Namespace_names.prefixed_string_of_rqname fn) 
				 ^ "' do not match function's signature.\n")))
let get_physical_opname algop = 
  match algop.palgop_expr_eval_sig with
  | None -> raise(Query(Code_Selection("Physical operator missing for logical operator "^
				       Xquery_algebra_ast_util.string_of_algop_expr_name algop.palgop_expr_name)))
  | Some (physop, _, _) -> physop

(*************************************)
(*********** Code Building ***********)
(*************************************)

let build_add_var_xml_value_with_ref code_ctxt vr = 
  let f = build_variable_store_code vr in
    (fun xv ->
     let mv = materialize_xml_value xv in
       f mv)

let build_add_var_item_list code_ctxt vname = 
  let f = build_current_insert_code code_ctxt vname in
  (fun il -> 
    let mv = xml_value_of_item_list il in
     f mv)

(* Code that can also have "unsafe" (i.e. non-materialized versions) *)

(* XML Values *)
let build_unsafe_fn code_ctxt bShould vn f =
  (* Converts a stream into the corresponding item sequence if streams are not
     explicitly allowed. This mimics the former conservative behaviour which was
     enforced at the Ocaml function signature level. - Michael *)
  if (bShould && not(!Conf.force_materialized_variables))
  then
    begin
      let buc =
	(get_bound_use_counts (retrieve_annotation "build_unsafe_fn" code_ctxt))
      in
      try
	match (List.assoc vn buc) with
	| (0,Never) -> (* unused variable *)
	    (fun xv -> ())
	| (1,Once) -> (* used only once, set unsafely *)
	    (fun xv -> f xv)
	| _ -> (* Should materialize *)
	    (fun xv -> f (materialize_xml_value xv))
      with Not_found ->
	raise (Query (Code_Selection ("Variable " 
				      ^ (Namespace_names.prefixed_string_of_rqname vn) ^
				      " not listed in bound during unsafe code building")))
    end
  else
    (fun xv -> f (materialize_xml_value xv))

(* Now binding an arbitrary xml_value here. - Michael *)
let build_add_var_xml_value code_ctxt bunsafe vname =
  let f = build_current_insert_code code_ctxt vname in
  let nf = build_unsafe_fn code_ctxt bunsafe vname f in 
  (fun xv -> nf xv)

(* item cursors *)
let build_add_var_item_cursor code_ctxt bunsafe vname =
  let f = build_current_insert_code code_ctxt vname in
  let f = build_unsafe_fn code_ctxt bunsafe vname f in 

  (fun ic ->
     let cv = xml_value_of_item_cursor ic in
       f cv)


(*********************)
(* These are exposed *)
(*********************)

let build_add_var_xml_value_unsafe_allowed code_ctxt vname =
  build_add_var_xml_value code_ctxt true vname 

let build_add_var_xml_value_safe code_ctxt vname =
  build_add_var_xml_value code_ctxt false vname 


let build_add_var_item_cursor_unsafe_allowed code_ctxt vname =
  build_add_var_item_cursor code_ctxt true vname

let build_add_var_item_cursor_safe code_ctxt vname =
  build_add_var_item_cursor code_ctxt false vname


(**************************************)
(********* RETRIEVING SECTION *********)
(**************************************)

let build_physical_value_retrieve code_ctxt vn =
  build_current_retrieve_code code_ctxt vn

let build_var_xml_value_retrieve code_ctxt vn =
  let retrieve = build_current_retrieve_code code_ctxt vn in
  (fun () -> (retrieve ()))

let build_var_item_list_retrieve code_ctxt vn =
  let retrieve = build_current_retrieve_code code_ctxt vn in
  (fun () -> item_list_of_xml_value (retrieve ()))


(****************)
(* Join Helpers *)
(****************)

let inputs_are_fs_untyped_to_any op =
  (* We know it is binary *)
  let ops = Xquery_algebra_ast_util.access_manysub op.psub_expression in 
  let l,r = (ops.(0), ops.(1)) in
    (is_fs_untyped_to_any l) && 
    (is_fs_untyped_to_any r)

(**********************************************)
(* This promotes according to all options of  *)
(*   fs:untyped-to-any                        *)
(* It has the semantic of value comparison
   type promotion. This is used in 
   distinct value comparisons for example.    *)
(**********************************************)
(* NOTE ABOUT xs:decimal. We promote it to double here. This
   fact is used below in our promotions. *)
let promote_to_highest t = 
  match t with
  | ATInteger | ATDecimal | ATFloat ->
      Some (Namespace_symbols_builtin.xs_double, ATDouble)
  | ATDouble -> None
	(* Untyped converted to double below, if possible *)
  | ATUntypedAtomic -> Some (Namespace_symbols_builtin.xs_string, ATString)
  | _ -> None

let promote_atomicValue_to_highest nsenv av = 
  let at = av#getAtomicValueKind () in
  match at with
  | ATInteger | ATDecimal | ATFloat ->
      av#cast_to nsenv Namespace_symbols_builtin.xs_double ATDouble
  | ATDouble -> av
	(* Untyped converted to double below, if possible *)
  | ATUntypedAtomic -> 
      av#cast_to nsenv Namespace_symbols_builtin.xs_string ATString
  | _ -> av

let promote_atomicValue_to_all nsenv av =
  let at = av#getAtomicValueKind () in
  match at with
  | ATUntypedAtomic ->
      [av;
       av#cast_to nsenv Namespace_symbols_builtin.xs_string ATString]
  | ATInteger ->
      [av;
       av#cast_to nsenv Namespace_symbols_builtin.xs_decimal ATDecimal;
       av#cast_to nsenv Namespace_symbols_builtin.xs_float ATFloat;
       av#cast_to nsenv Namespace_symbols_builtin.xs_double ATDouble]
  | ATDecimal ->
      [av;
       av#cast_to nsenv Namespace_symbols_builtin.xs_float ATFloat;
       av#cast_to nsenv Namespace_symbols_builtin.xs_double ATDouble]
  | ATFloat ->
      [av;
       av#cast_to nsenv Namespace_symbols_builtin.xs_double ATDouble]
  | ATDouble ->
      [av]
  | ATYearMonthDuration | ATDayTimeDuration ->
      [av;av#cast_to nsenv Namespace_symbols_builtin.xs_duration ATDuration]
  | _ ->
      [av]

(* Handles the fs_untyped to any semantic
   
   Returns a pair (v1,v2 option).

   If the value is typed: 

   v1 is the value promoted to its "highest" type.
   v2 is the value in its original type 
         or None if type(v1) = type(v2)

   If the value is untyped:
   v1 is it as a string
   v2 is the value promoted to a double if possible
*)
let handle_fs_untyped_to_any_semantic nsenv av =
  (* Promote numeric types -> double
     promote untyped       -> string *)   
  let orig_at =  (av#getAtomicValueKind ()) in
  let changed = promote_to_highest orig_at in
  let v1 = (* Cast it if necessary *)
    match changed with
    | None -> av
    | Some (new_atn, new_at) ->
	av#cast_to nsenv new_atn new_at
  in
  let v2 =
    (* This is nasty - but ocaml does not 
       provide a simple way to check if this condition
       is valid (essentially whether float_of_string will fail).
       So it makes us use exceptions on the critical path
       of the join - we need to eliminate this *)
    (* This should probably be hand-coded as lexing doubles
       is absurdly expensive for what it is doing *)
    match orig_at with      
    | ATUntypedAtomic -> 
	begin
	  try
	    Some (av#cast_to nsenv Namespace_symbols_builtin.xs_double ATDouble)
	  with  _ ->
	      None
	end
    | _ -> match changed with Some _ -> Some av | None -> None 
  in
    v1, v2

(**********************************************************)
(* RQName demangling for Distributed XQuery dxq: protocol *)
(**********************************************************)
let mangle_prefix = Pcre.regexp "^dxq:"

let dxq_demangle_rqname = function
    (x,Namespace_names.NSUri y,z) ->
      if Pcre.pmatch ~rex:mangle_prefix y then
        let demangled_y = Pcre.replace ~rex:mangle_prefix ~templ:"" y in
        Some (x,Namespace_names.NSUri demangled_y,z)
      else None
  | _ -> None