def perform_subquery(self, allowed_platforms, dbgraph, user, query_plan): """ Connect a new AST to the current AST using a SubQuery Node. If the connected table is "on join", we will use a LeftJoin and a CrossProduct Node instead. Args: dbgraph: The DBGraph instance related to the 3nf graph. allowed_platforms: A set of String where each String correponds to a queried platform name. user: The User issuing the Query. query_plan: The QueryPlan instance related to this Query, and that we're updating. """ # We need to build an AST just to collect subqueries #OBSOLETE| # XXX dbgraph not defined #OBSOLETE| #if not self.ast: #OBSOLETE| # self.ast = self.build_union(self.root, self.keep_root_a, dbgraph, user) #OBSOLETE| if not self.ast: #OBSOLETE| fields = set() #OBSOLETE| for _, (_, relation) in self.subqueries.items(): #OBSOLETE| fields |= relation.get_predicate().get_field_names() #OBSOLETE| self.ast = self.build_union(self.root, fields, allowed_platforms, dbgraph, user, query_plan) if not self.ast: self.perform_union_all(self.root, allowed_platforms, dbgraph, user, query_plan) if self.root.capabilities.is_onjoin(): # Let's identify tables involved in the key root_key_fields = self.root.keys.one().get_field_names() xp_ast_relation, sq_ast_relation = [], [] xp_key = () xp_value = () for name, ast_relation in self.subqueries.items(): if name in root_key_fields: ast, relation = ast_relation key, _, value = relation.get_predicate().get_tuple() xp_key += (value, ) xp_value += (key, ) xp_ast_relation.append(ast_relation) else: sq_ast_relation.append(ast_relation) ast = self.ast if sq_ast_relation: ast.subquery(sq_ast_relation) query = Query.action('get', self.root.get_name()).select(set(xp_key)) self.ast = AST().cross_product(xp_ast_relation, query) predicate = Predicate(xp_key, eq, xp_value) self.ast.left_join(ast, predicate) else: self.ast.subquery(self.subqueries.values())
def perform_union_all(self, table, allowed_platforms, dbgraph, user, query_plan): #OBSOLETE| def build_union(self, table, needed_fields, allowed_platforms, dbgraph, user, query_plan): """ Complete a QueryPlan instance by adding an Union of From Node related to a same Table. Args: table: The 3nf Table, potentially provided by several platforms. allowed_platforms: A set of String where each String correponds to a queried platform name. user: The User issuing the Query. query_plan: The QueryPlan instance related to this Query, and that we're updating. """ from_asts = list() key = table.get_keys().one() #MANDO|DEPRECATED| # TO BE REMOVED ? #MANDO|DEPRECATED| # Exploring this tree according to a DFS algorithm leads to a table #MANDO|DEPRECATED| # ordering leading to feasible successive joins #MANDO|DEPRECATED| map_method_bestkey = dict() #MANDO|DEPRECATED|#DEPRECATED|LOIC| map_method_demux = dict() #MANDO|DEPRECATED| #MANDO|DEPRECATED| # XXX I don't understand this -- Jordan #MANDO|DEPRECATED| # Update the key used by a given method #MANDO|DEPRECATED| # The more we iterate, the best the key is #MANDO|DEPRECATED| if key: #MANDO|DEPRECATED| for method, keys in table.map_method_keys.items(): #MANDO|DEPRECATED| if key in table.map_method_keys[method]: #MANDO|DEPRECATED| map_method_bestkey[method] = key # For each platform related to the current table, extract the # corresponding table and build the corresponding FROM node map_method_fields = table.get_annotations() for method, fields in map_method_fields.items(): # The table announced by the platform fits with the 3nf schema # Build the corresponding FROM #sub_table = Table.make_table_from_platform(table, fields, method.get_platform()) platform = method.get_platform() capabilities = dbgraph.get_capabilities(platform, method.get_name()) map_field_local = { f.get_name(): f.is_local() for f in table.get_fields() } selected_fields = set( [f for f in fields if not map_field_local[f]]) selected_fields |= self.keep_root_a if not capabilities.projection: all_fields = set([f.get_name() for f in table.get_fields()]) # IN 3NF, this is not necessarily all fields selected_fields = all_fields # We create 'get' queries by default, this will be overriden in set_ast query = Query.action('get', method.get_name()).select(selected_fields) #query = Query.action('get', method.get_name()).select(fields) if not platform in allowed_platforms: continue # The current platform::table might be ONJOIN (no retrieve capability), but we # might be able to collect the keys, so we have disabled the following code # XXX Improve platform capabilities support if self.relation is None and not capabilities.retrieve: continue from_ast = AST(user=user).From(platform, query, capabilities, key) if from_ast: query_plan.add_from(from_ast.get_root()) self.perform_union((from_ast, dict()), key, allowed_platforms, dbgraph, user, query_plan)