rqlrewrite.py
branchstable
changeset 7843 3b51806da60b
parent 7555 c3bf459268d7
child 7850 d14b77c42b06
equal deleted inserted replaced
7842:fa7e463cae9d 7843:3b51806da60b
   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