def _translate_term(self, node): """Pushes an element onto the operand stack.""" v = node.value if isinstance(v, ast.Scalar): self._operands[-1].append(sql.Constant(v.value)) elif isinstance(v, ast.Ref) and len(v.terms) == 3: table = v.terms[1].value.value self._tables.add(table) col = sql.Column(v.terms[2].value.value, table) self._operands[-1].append(col) elif isinstance(v, ast.Call): try: op = v.op() sql_op = self._sql_call_operators[op] except KeyError: raise TranslationError( 'invalid call: operator not supported: %s' % op) self._operands.append([]) for term in v.operands: walk.walk(term, self) sql_operands = self._operands.pop() self._operands[-1].append(sql.Call(sql_op, sql_operands)) else: raise TranslationError('invalid term: type not supported: %s' % v.__class__.__name__)
def _translate_expr(self, node): """Pushes an element onto the relation stack.""" builtinFunctionType = False if not node.is_call(): return if len(node.operands) != 2: raise TranslationError('invalid expression: too many arguments') try: op = node.op() sql_op = sql.RelationOp(self._sql_relation_operators[op]) except KeyError: try: sql_op = sql.RelationOp( self._sql_built_in_binary_operators[op]) builtinFunctionType = True except KeyError: raise TranslationError( 'invalid expression: operator not supported: %s' % op) self._operands.append([]) for term in node.operands: walk.walk(term, self) sql_operands = self._operands.pop() if builtinFunctionType: self._relations.append( sql.BuiltInBinaryFunction(sql_op, *sql_operands)) else: self._relations.append(sql.Relation(sql_op, *sql_operands))
def __call__(self, node): if isinstance(node, ast.Query): self._table_names.append({}) self._table_vars = {} elif isinstance(node, ast.Expr): if node.is_call(): # Skip the built-in call operator. for o in node.operands: walk.walk(o, self) return elif isinstance(node, ast.Call): # Skip the call operator. for o in node.operands: walk.walk(o, self) return elif isinstance(node, ast.Ref): head = node.terms[0].value.value if head in self._table_vars: # Expand ref in case head was an intermediate var. E.g., # "data.foo[x]; x.bar" => "data.foo[x]; data.foo.bar". node.terms = self._table_vars[head] + node.terms[1:] return row_id = node.terms[2].value # Refs must be of the form data.<table>[<iterator>].<column>. if not isinstance(row_id, ast.Var): raise TranslationError( 'invalid reference: row identifier type not supported: %s' % row_id.__class__.__name__) prefix = node.terms[:2] # Add mapping so that we can expand refs above. self._table_vars[row_id.value] = prefix table_name = node.terms[1].value.value # Keep track of iterators used for each table. We do not support # self-joins currently. Self-joins require namespacing in the SQL # query. exist = self._table_names[-1].get(table_name, row_id.value) if exist != row_id.value: raise TranslationError( 'invalid reference: self-joins not supported') else: self._table_names[-1][table_name] = row_id.value # Rewrite ref to remove iterator var. E.g., "data.foo[x].bar" => # "data.foo.bar". node.terms = prefix + node.terms[3:] return return self
def translate(self, query_set): """Returns a :class:`sql.Union` containing :class:`sql.Where` and :class:`sql.InnerJoin` clauses to be applied to the query.""" walk.walk(query_set, self) clauses = [] if len(self._conjunctions) > 0: clauses = [sql.Where(sql.Disjunction([conj for conj in self._conjunctions]))] for (tables, conj) in self._joins: pred = sql.InnerJoin(tables, conj) clauses.append(pred) return sql.Union(clauses)
def _translate_query(self, node): """Pushes an expression onto the conjunction or join stack if multiple tables are referred to.""" for expr in node.exprs: walk.walk(expr, self) conj = sql.Conjunction(self._relations) if len(self._tables) > 1: self._tables.remove(self._from_table) self._joins.append((self._tables, conj)) else: self._conjunctions.append(conj) self._tables = set([]) self._relations = []
def _translate_expr(self, node): """Pushes an element onto the relation stack.""" if not node.is_call(): return if len(node.operands) != 2: raise TranslationError('invalid expression: too many arguments') try: op = node.op() sql_op = sql.RelationOp(self._sql_relation_operators[op]) except KeyError: raise TranslationError('invalid expression: operator not supported: %s' % op) self._operands.append([]) for term in node.operands: walk.walk(term, self) sql_operands = self._operands.pop() self._relations.append(sql.Relation(sql_op, *sql_operands))
def process(self, query_set): walk.walk(query_set, self)