334 self._lock.acquire() |
334 self._lock.acquire() |
335 self._args = args |
335 self._args = args |
336 self._varmap = varmap |
336 self._varmap = varmap |
337 self._query_attrs = {} |
337 self._query_attrs = {} |
338 self._state = None |
338 self._state = None |
|
339 self._not_scope_offset = 0 |
339 try: |
340 try: |
340 # union query for each rqlst / solution |
341 # union query for each rqlst / solution |
341 sql = self.union_sql(union) |
342 sql = self.union_sql(union) |
342 # we are done |
343 # we are done |
343 return sql, self._query_attrs |
344 return sql, self._query_attrs |
551 return res[0] |
552 return res[0] |
552 return '' |
553 return '' |
553 |
554 |
554 def visit_not(self, node): |
555 def visit_not(self, node): |
555 self._state.push_scope() |
556 self._state.push_scope() |
|
557 if isinstance(node.children[0], Relation): |
|
558 self._not_scope_offset += 1 |
556 csql = node.children[0].accept(self) |
559 csql = node.children[0].accept(self) |
|
560 if isinstance(node.children[0], Relation): |
|
561 self._not_scope_offset -= 1 |
557 sqls, tables = self._state.pop_scope() |
562 sqls, tables = self._state.pop_scope() |
558 if node in self._state.done or not csql: |
563 if node in self._state.done or not csql: |
559 # already processed or no sql generated by children |
564 # already processed or no sql generated by children |
560 self._state.actual_tables[-1] += tables |
565 self._state.actual_tables[-1] += tables |
561 self._state.restrictions += sqls |
566 self._state.restrictions += sqls |
649 return |
654 return |
650 # OPTIONAL relation, generate a left|right outer join |
655 # OPTIONAL relation, generate a left|right outer join |
651 sql = self._visit_outer_join_relation(relation, rschema) |
656 sql = self._visit_outer_join_relation(relation, rschema) |
652 elif rschema.inlined: |
657 elif rschema.inlined: |
653 sql = self._visit_inlined_relation(relation) |
658 sql = self._visit_inlined_relation(relation) |
654 # elif isinstance(relation.parent, Not): |
|
655 # self._state.done.add(relation.parent) |
|
656 # # NOT relation |
|
657 # sql = self._visit_not_relation(relation, rschema) |
|
658 else: |
659 else: |
659 # regular (non final) relation |
660 # regular (non final) relation |
660 sql = self._visit_relation(relation, rschema) |
661 sql = self._visit_relation(relation, rschema) |
661 return sql |
662 return sql |
662 |
663 |
1078 # if current var or one of its attribute is selected , it *must* |
1079 # if current var or one of its attribute is selected , it *must* |
1079 # appear in the toplevel's FROM even if we're currently visiting |
1080 # appear in the toplevel's FROM even if we're currently visiting |
1080 # a EXISTS node |
1081 # a EXISTS node |
1081 if var.sqlscope is var.stmt: |
1082 if var.sqlscope is var.stmt: |
1082 scope = 0 |
1083 scope = 0 |
|
1084 # don't consider not_scope_offset if the variable is only used in one |
|
1085 # relation |
|
1086 elif len(var.stinfo['relations']) > 1: |
|
1087 scope = -1 - self._not_scope_offset |
1083 else: |
1088 else: |
1084 scope = -1 |
1089 scope = -1 |
1085 try: |
1090 try: |
1086 sql = self._varmap[var.name] |
1091 sql = self._varmap[var.name] |
1087 table = sql.split('.', 1)[0] |
1092 table = sql.split('.', 1)[0] |
1088 if scope == -1: |
1093 if scope < 0: |
1089 scope = self._varmap_table_scope(var.stmt, table) |
1094 scope = self._varmap_table_scope(var.stmt, table) |
1090 self.add_table(table, scope=scope) |
1095 self.add_table(table, scope=scope) |
1091 except KeyError: |
1096 except KeyError: |
1092 etype = self._state.solution[var.name] |
1097 etype = self._state.solution[var.name] |
1093 # XXX this check should be moved in rql.stcheck |
1098 # XXX this check should be moved in rql.stcheck |
1094 if self.schema.eschema(etype).is_final(): |
1099 if self.schema.eschema(etype).is_final(): |
1095 raise BadRQLQuery(var.stmt.root) |
1100 raise BadRQLQuery(var.stmt.root) |
1096 table = var.name |
1101 table = var.name |
1097 sql = '%s.%seid' % (table, SQL_PREFIX) |
1102 sql = '%s.%seid' % (table, SQL_PREFIX) |
1098 self.add_table('%s%s AS %s' % (SQL_PREFIX, etype, table), table, scope=scope) |
1103 self.add_table('%s%s AS %s' % (SQL_PREFIX, etype, table), table, |
|
1104 scope=scope) |
1099 return sql, table |
1105 return sql, table |
1100 |
1106 |
1101 def _inlined_var_sql(self, var, rtype): |
1107 def _inlined_var_sql(self, var, rtype): |
1102 try: |
1108 try: |
1103 sql = self._varmap['%s.%s' % (var.name, rtype)] |
1109 sql = self._varmap['%s.%s' % (var.name, rtype)] |
1144 def add_table(self, table, key=None, scope=-1): |
1150 def add_table(self, table, key=None, scope=-1): |
1145 if key is None: |
1151 if key is None: |
1146 key = table |
1152 key = table |
1147 if key in self._state.tables: |
1153 if key in self._state.tables: |
1148 return |
1154 return |
1149 if scope == -1: |
1155 if scope < 0: |
1150 scope = len(self._state.actual_tables) - 1 |
1156 scope = len(self._state.actual_tables) + scope |
1151 self._state.tables[key] = (scope, table) |
1157 self._state.tables[key] = (scope, table) |
1152 self._state.actual_tables[scope].append(table) |
1158 self._state.actual_tables[scope].append(table) |
1153 |
1159 |
1154 def replace_tables_by_outer_join(self, substitute, lefttable, *tables): |
1160 def replace_tables_by_outer_join(self, substitute, lefttable, *tables): |
1155 for table in tables: |
1161 for table in tables: |