335 |
335 |
336 def snippet_subquery(self, varmap, transformedsnippet): |
336 def snippet_subquery(self, varmap, transformedsnippet): |
337 """introduce the given snippet in a subquery""" |
337 """introduce the given snippet in a subquery""" |
338 subselect = stmts.Select() |
338 subselect = stmts.Select() |
339 snippetrqlst = n.Exists(transformedsnippet.copy(subselect)) |
339 snippetrqlst = n.Exists(transformedsnippet.copy(subselect)) |
|
340 get_rschema = self.schema.rschema |
340 aliases = [] |
341 aliases = [] |
341 rels_done = set() |
342 done = set() |
342 for i, (selectvar, snippetvar) in enumerate(varmap): |
343 for i, (selectvar, _) in enumerate(varmap): |
|
344 need_null_test = False |
343 subselectvar = subselect.get_variable(selectvar) |
345 subselectvar = subselect.get_variable(selectvar) |
344 subselect.append_selected(n.VariableRef(subselectvar)) |
346 subselect.append_selected(n.VariableRef(subselectvar)) |
345 aliases.append(selectvar) |
347 aliases.append(selectvar) |
346 vi = self.varinfos[i] |
348 todo = [(selectvar, self.varinfos[i]['stinfo'])] |
347 need_null_test = False |
349 while todo: |
348 stinfo = vi['stinfo'] |
350 varname, stinfo = todo.pop() |
349 for rel in stinfo['relations']: |
351 done.add(varname) |
350 if rel in rels_done: |
352 for rel in stinfo['relations'] - stinfo['rhsrelations']: |
351 continue |
353 if rel in done: |
352 rels_done.add(rel) |
354 continue |
353 rschema = self.schema.rschema(rel.r_type) |
355 done.add(rel) |
354 if rschema.final or (rschema.inlined and |
356 rschema = get_rschema(rel.r_type) |
355 not rel in stinfo['rhsrelations']): |
357 if rschema.final or rschema.inlined: |
356 rel.children[0].name = selectvar # XXX explain why |
358 rel.children[0].name = varname # XXX explain why |
357 subselect.add_restriction(rel.copy(subselect)) |
359 subselect.add_restriction(rel.copy(subselect)) |
358 for vref in rel.children[1].iget_nodes(n.VariableRef): |
360 for vref in rel.children[1].iget_nodes(n.VariableRef): |
359 if isinstance(vref.variable, n.ColumnAlias): |
361 if isinstance(vref.variable, n.ColumnAlias): |
360 # XXX could probably be handled by generating the |
362 # XXX could probably be handled by generating the |
361 # subquery into the detected subquery |
363 # subquery into the detected subquery |
362 raise BadSchemaDefinition( |
364 raise BadSchemaDefinition( |
363 "cant insert security because of usage two inlined " |
365 "cant insert security because of usage two inlined " |
364 "relations in this query. You should probably at " |
366 "relations in this query. You should probably at " |
365 "least uninline %s" % rel.r_type) |
367 "least uninline %s" % rel.r_type) |
366 subselect.append_selected(vref.copy(subselect)) |
368 subselect.append_selected(vref.copy(subselect)) |
367 aliases.append(vref.name) |
369 aliases.append(vref.name) |
368 self.select.remove_node(rel) |
370 self.select.remove_node(rel) |
369 # when some inlined relation has to be copied in the |
371 # when some inlined relation has to be copied in the |
370 # subquery, we need to test that either value is NULL or |
372 # subquery and that relation is optional, we need to |
371 # that the snippet condition is satisfied |
373 # test that either value is NULL or that the snippet |
372 if rschema.inlined and rel.optional: |
374 # condition is satisfied |
373 need_null_test = True |
375 if varname == selectvar and rel.optional and rschema.inlined: |
|
376 need_null_test = True |
|
377 # also, if some attributes or inlined relation of the |
|
378 # object variable are accessed, we need to get all those |
|
379 # from the subquery as well |
|
380 if vref.name not in done and rschema.inlined: |
|
381 # we can use vref here define in above for loop |
|
382 ostinfo = vref.variable.stinfo |
|
383 for orel in ostinfo['relations'] - ostinfo['rhsrelations']: |
|
384 orschema = get_rschema(orel.r_type) |
|
385 if orschema.final or orschema.inlined: |
|
386 todo.append( (vref.name, ostinfo) ) |
|
387 break |
374 if need_null_test: |
388 if need_null_test: |
375 snippetrqlst = n.Or( |
389 snippetrqlst = n.Or( |
376 n.make_relation(subselectvar, 'is', (None, None), n.Constant, |
390 n.make_relation(subselect.get_variable(selectvar), 'is', |
|
391 (None, None), n.Constant, |
377 operator='='), |
392 operator='='), |
378 snippetrqlst) |
393 snippetrqlst) |
379 subselect.add_restriction(snippetrqlst) |
394 subselect.add_restriction(snippetrqlst) |
380 if self.u_varname: |
395 if self.u_varname: |
381 # generate an identifier for the substitution |
396 # generate an identifier for the substitution |