152 # Plans ####################################################################### |
152 # Plans ####################################################################### |
153 |
153 |
154 class ExecutionPlan(object): |
154 class ExecutionPlan(object): |
155 """the execution model of a rql query, composed of querier steps""" |
155 """the execution model of a rql query, composed of querier steps""" |
156 |
156 |
157 def __init__(self, querier, rqlst, args, cnx): |
157 def __init__(self, schema, rqlst, args, cnx): |
|
158 self.schema = schema |
158 # original rql syntax tree |
159 # original rql syntax tree |
159 self.rqlst = rqlst |
160 self.rqlst = rqlst |
160 self.args = args or {} |
161 self.args = args or {} |
161 # cnx executing the query |
162 # cnx executing the query |
162 self.cnx = cnx |
163 self.cnx = cnx |
163 # execution steps |
164 # execution steps |
164 self.steps = [] |
165 self.steps = [] |
165 self.querier = querier |
|
166 # tracing token for debugging |
166 # tracing token for debugging |
167 self.rql_query_tracing_token = None |
167 self.rql_query_tracing_token = None |
168 |
168 |
169 def add_step(self, step): |
169 def add_step(self, step): |
170 """add a step to the plan""" |
170 """add a step to the plan""" |
209 self.cnx.transaction_data[key] = (union, self.args) |
209 self.cnx.transaction_data[key] = (union, self.args) |
210 else: |
210 else: |
211 noinvariant = () |
211 noinvariant = () |
212 if cached is None: |
212 if cached is None: |
213 self.cnx.vreg.rqlhelper.simplify(union) |
213 self.cnx.vreg.rqlhelper.simplify(union) |
214 RQLAnnotator(self.querier.schema).annotate(union) |
214 RQLAnnotator(self.schema).annotate(union) |
215 set_qdata(self.querier.schema.rschema, union, noinvariant) |
215 set_qdata(self.schema.rschema, union, noinvariant) |
216 if union.has_text_query: |
216 if union.has_text_query: |
217 self.cache_key = None |
217 self.cache_key = None |
218 |
218 |
219 def _insert_security(self, union): |
219 def _insert_security(self, union): |
220 noinvariant = set() |
220 noinvariant = set() |
306 for mainvarname, rschema, newvarname in insertedvars: |
306 for mainvarname, rschema, newvarname in insertedvars: |
307 nvartype = str(rschema.objects(solutions[0][mainvarname])[0]) |
307 nvartype = str(rschema.objects(solutions[0][mainvarname])[0]) |
308 for sol in solutions: |
308 for sol in solutions: |
309 sol[newvarname] = nvartype |
309 sol[newvarname] = nvartype |
310 select.clean_solutions(solutions) |
310 select.clean_solutions(solutions) |
311 add_types_restriction(self.querier.schema, select) |
311 add_types_restriction(self.schema, select) |
312 self.cnx.vreg.rqlhelper.annotate(rqlst) |
312 self.cnx.vreg.rqlhelper.annotate(rqlst) |
313 self.preprocess(rqlst, security=False) |
313 self.preprocess(rqlst, security=False) |
314 return rqlst |
314 return rqlst |
315 |
315 |
316 |
316 |
317 class InsertPlan(ExecutionPlan): |
317 class InsertPlan(ExecutionPlan): |
318 """an execution model specific to the INSERT rql query |
318 """an execution model specific to the INSERT rql query |
319 """ |
319 """ |
320 |
320 |
321 def __init__(self, querier, rqlst, args, cnx): |
321 def __init__(self, schema, rqlst, args, cnx): |
322 ExecutionPlan.__init__(self, querier, rqlst, args, cnx) |
322 ExecutionPlan.__init__(self, schema, rqlst, args, cnx) |
323 # save originally selected variable, we may modify this |
323 # save originally selected variable, we may modify this |
324 # dictionary for substitution (query parameters) |
324 # dictionary for substitution (query parameters) |
325 self.selected = rqlst.selection |
325 self.selected = rqlst.selection |
326 # list of rows of entities definition (ssplanner.EditedEntity) |
326 # list of rows of entities definition (ssplanner.EditedEntity) |
327 self.e_defs = [[]] |
327 self.e_defs = [[]] |
337 self.e_defs[-1].append(edef) |
337 self.e_defs[-1].append(edef) |
338 |
338 |
339 def add_relation_def(self, rdef): |
339 def add_relation_def(self, rdef): |
340 """add an relation definition to build""" |
340 """add an relation definition to build""" |
341 edef, rtype, value = rdef |
341 edef, rtype, value = rdef |
342 if self.querier.schema[rtype].rule: |
342 if self.schema[rtype].rule: |
343 raise QueryError("'%s' is a computed relation" % rtype) |
343 raise QueryError("'%s' is a computed relation" % rtype) |
344 self.r_defs.add(rdef) |
344 self.r_defs.add(rdef) |
345 if not isinstance(edef, int): |
345 if not isinstance(edef, int): |
346 self._r_subj_index.setdefault(edef, []).append(rdef) |
346 self._r_subj_index.setdefault(edef, []).append(rdef) |
347 if not isinstance(value, int): |
347 if not isinstance(value, int): |
485 cache.pop(('%s X WHERE X eid %s' % (etype, eid),), None) |
485 cache.pop(('%s X WHERE X eid %s' % (etype, eid),), None) |
486 |
486 |
487 def plan_factory(self, rqlst, args, cnx): |
487 def plan_factory(self, rqlst, args, cnx): |
488 """create an execution plan for an INSERT RQL query""" |
488 """create an execution plan for an INSERT RQL query""" |
489 if rqlst.TYPE == 'insert': |
489 if rqlst.TYPE == 'insert': |
490 return InsertPlan(self, rqlst, args, cnx) |
490 return InsertPlan(self.schema, rqlst, args, cnx) |
491 return ExecutionPlan(self, rqlst, args, cnx) |
491 return ExecutionPlan(self.schema, rqlst, args, cnx) |
492 |
492 |
493 @statsd_timeit |
493 @statsd_timeit |
494 def execute(self, cnx, rql, args=None, build_descr=True): |
494 def execute(self, cnx, rql, args=None, build_descr=True): |
495 """execute a rql query, return resulting rows and their description in |
495 """execute a rql query, return resulting rows and their description in |
496 a `ResultSet` object |
496 a `ResultSet` object |