diff -r 672acc730ce5 -r d628defebc17 server/querier.py --- a/server/querier.py Thu May 14 10:24:56 2009 +0200 +++ b/server/querier.py Thu May 14 11:38:40 2009 +0200 @@ -2,7 +2,7 @@ security checking and data aggregation. :organization: Logilab -:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr """ __docformat__ = "restructuredtext en" @@ -84,7 +84,7 @@ #assert len(erqlexprs) == 1 localchecks[varname] = tuple(erqlexprs) return localchecks - + def noinvariant_vars(restricted, select, nbtrees): # a variable can actually be invariant if it has not been restricted for # security reason or if security assertion hasn't modified the possible @@ -114,12 +114,12 @@ colalias = newselect.get_variable(vref.name, len(aliases)) aliases.append(VariableRef(colalias)) selected.add(vref.name) - + # Plans ####################################################################### class ExecutionPlan(object): """the execution model of a rql query, composed of querier steps""" - + def __init__(self, querier, rqlst, args, session): # original rql syntax tree self.rqlst = rqlst @@ -137,11 +137,11 @@ self.schema = querier.schema self.rqlhelper = querier._rqlhelper self.sqlannotate = querier.sqlgen_annotate - + def annotate_rqlst(self): if not self.rqlst.annotated: self.rqlhelper.annotate(self.rqlst) - + def add_step(self, step): """add a step to the plan""" self.steps.append(step) @@ -149,10 +149,10 @@ def clean(self): """remove temporary tables""" self.syssource.clean_temp_data(self.session, self.temp_tables) - + def sqlexec(self, sql, args=None): return self.syssource.sqlexec(self.session, sql, args) - + def execute(self): """execute a plan and return resulting rows""" try: @@ -162,7 +162,7 @@ return result finally: self.clean() - + def init_temp_table(self, table, selected, sol): """initialize sql schema and variable map for a temporary table which will be used to store result for the given rqlst @@ -175,17 +175,17 @@ table) self.temp_tables[table] = [outputmap, sqlschema, False] return outputmap - + def create_temp_table(self, table): """create a temporary table to store result for the given rqlst""" if not self.temp_tables[table][-1]: sqlschema = self.temp_tables[table][1] self.syssource.create_temp_table(self.session, table, sqlschema) self.temp_tables[table][-1] = True - + def preprocess(self, union, security=True): """insert security when necessary then annotate rql st for sql generation - + return rqlst to actually execute """ #if server.DEBUG: @@ -279,7 +279,7 @@ are removed, else if the user may read it (eg if an rql expression is defined for the "read" permission of the related type), the local checks dict for the solution is updated - + return a dict with entries for each different local check necessary, with associated solutions as value. A local check is defined by a list of 2-uple, with variable name as first item and the necessary rql @@ -346,11 +346,11 @@ self.rqlhelper.annotate(rqlst) self.preprocess(rqlst, security=False) return rqlst - + class InsertPlan(ExecutionPlan): """an execution model specific to the INSERT rql query """ - + def __init__(self, querier, rqlst, args, session): ExecutionPlan.__init__(self, querier, rqlst, args, session) # save originaly selected variable, we may modify this @@ -387,7 +387,7 @@ value = rhs.eval(self.args) eschema = edef.e_schema attrtype = eschema.subject_relation(rtype).objects(eschema)[0] - if attrtype == 'Password' and isinstance(value, unicode): + if attrtype == 'Password' and isinstance(value, unicode): value = value.encode('UTF8') edef[rtype] = value elif to_build.has_key(str(rhs)): @@ -397,12 +397,12 @@ to_select.setdefault(edef, []).append( (rtype, rhs, 0) ) return to_select - + def add_entity_def(self, edef): """add an entity definition to build""" edef.querier_pending_relations = {} self.e_defs[-1].append(edef) - + def add_relation_def(self, rdef): """add an relation definition to build""" self.r_defs.append(rdef) @@ -410,11 +410,11 @@ self._r_subj_index.setdefault(rdef[0], []).append(rdef) if not isinstance(rdef[2], int): self._r_obj_index.setdefault(rdef[2], []).append(rdef) - + def substitute_entity_def(self, edef, edefs): """substitute an incomplete entity definition by a list of complete equivalents - + e.g. on queries such as :: INSERT Personne X, Societe Y: X nom N, Y nom 'toto', X travaille Y WHERE U login 'admin', U login N @@ -455,7 +455,7 @@ for edef in edefs: result.append( (exp_rdef[0], exp_rdef[1], edef) ) self._expanded_r_defs[rdef] = result - + def _expanded(self, rdef): """return expanded value for the given relation definition""" try: @@ -463,7 +463,7 @@ except KeyError: self.r_defs.remove(rdef) return [rdef] - + def relation_defs(self): """return the list for relation definitions to insert""" for rdefs in self._expanded_r_defs.values(): @@ -471,11 +471,11 @@ yield rdef for rdef in self.r_defs: yield rdef - + def insert_entity_defs(self): """return eids of inserted entities in a suitable form for the resulting result set, e.g.: - + e.g. on queries such as :: INSERT Personne X, Societe Y: X nom N, Y nom 'toto', X travaille Y WHERE U login 'admin', U login N @@ -490,7 +490,7 @@ results.append([repo.glob_add_entity(session, edef) for edef in row]) return results - + def insert_relation_defs(self): session = self.session repo = session.repo @@ -514,18 +514,18 @@ class QuerierHelper(object): """helper class to execute rql queries, putting all things together""" - + def __init__(self, repo, schema): # system info helper self._repo = repo # application schema self.set_schema(schema) - + def set_schema(self, schema): self.schema = schema # rql parsing / analysing helper self._rqlhelper = RQLHelper(schema, special_relations={'eid': 'uid', - 'has_text': 'fti'}) + 'has_text': 'fti'}) self._rql_cache = Cache(self._repo.config['rql-cache-size']) self.cache_hit, self.cache_miss = 0, 0 # rql planner @@ -535,11 +535,11 @@ from cubicweb.server.ssplanner import SSPlanner self._planner = SSPlanner(schema, self._rqlhelper) else: - from cubicweb.server.msplanner import MSPlanner + from cubicweb.server.msplanner import MSPlanner self._planner = MSPlanner(schema, self._rqlhelper) # sql generation annotator self.sqlgen_annotate = SQLGenAnnotator(schema).annotate - + def parse(self, rql, annotate=False): """return a rql syntax tree for the given rql""" try: @@ -559,7 +559,7 @@ if rqlst.TYPE == 'insert': return InsertPlan(self, rqlst, args, session) return ExecutionPlan(self, rqlst, args, session) - + def execute(self, session, rql, args=None, eid_key=None, build_descr=True): """execute a rql query, return resulting rows and their description in a `ResultSet` object @@ -578,7 +578,7 @@ on INSERT queries, there will be on row with the eid of each inserted entity - + result for DELETE and SET queries is undefined yet to maximize the rql parsing/analyzing cache performance, you should