def validateSubtree(self, context: StatementContext, relexpr): self.inputs[0].validateSubtree(context, relexpr) try: self.type = context.check.function_call(symbolic(self.op), [self.inputs[0].type]) except TypeSysError as e: raise ValidationError(str(e), self, relexpr) from e
def info(self): yield '{} => {}'.format(symbolic(sym.AGGR), self.type) for groupby in self.groupbys: yield '|group by: ' + groupby.info() for aggr in self.aggrs: yield '|' + aggr.info() for i, line in enumerate(self.inputs[0].info()): yield ('\\_' if i == 0 else ' ') + line
def validateSubtree(self, context: StatementContext): self.inputs[0].validateSubtree(context) self.inputs[1].validateSubtree(context) if self.cond is None: self.pairs = list() for i0, a0 in enumerate(self.inputs[0].type.attrs): if a0.name is None: continue matches = [(i1, a1) for i1, a1 in enumerate(self.inputs[1].type.attrs)\ if a0.name == a1.name] if len(matches) > 1: raise self.validationError('ambiguity in natural join: {} from the left input' ' matches multiple attributes on the right'\ .format(a0.str_ref_only())) elif len(matches) == 1: i1, a1 = matches[0] try: context.check.function_call(symbolic(sym.EQ), [a0.type, a1.type]) except TypeSysError as e: raise self.validationError('natural join cannot equate {} and {}'\ .format(a0, a1)) self.pairs.append((i0, i1)) if len(self.pairs) == 0: logger.warning('{}: no attributes with matching names found;' ' natural join degnerates into cross product'.format(self)) for i0, i1 in self.pairs: if any((j0, j1) for j0, j1 in self.pairs if j0 != i0 and j1 == i1): raise self.validationError('ambiguity in natural join: {} from the right input' ' matches multiple attributes on the left'\ .format(self.inputs[1].type.attrs[i1]\ .str_ref_only())) attrspecs = list() for a0 in self.inputs[0].type.attrs: attrspecs.append(a0) for i1, a1 in enumerate(self.inputs[1].type.attrs): if not any(i1 == i for _, i in self.pairs): attrspecs.append(a1) if any(a1.can_be_confused_with(a0) for a0 in self.inputs[0].type.attrs): # this shouldn't happen under natural join rule, but oh well: logger.warning('{}: attribute {} becomes confused with others' ' in the join output'\ .format(self, a1.str_ref_only())) self.type = RelType(context.new_tmp(), attrspecs) else: self.cond.validateSubtree(context, self) if self.cond.type != ValType.BOOLEAN: raise self.validationError('join condition {} has type {}; boolean expected'\ .format(self.cond, self.cond.type.value)) for a0, a1 in itertools.product(self.inputs[0].type.attrs, self.inputs[1].type.attrs): if a0.can_be_confused_with(a1): logger.warning('{}: attributes {} from the left input and {} from the right' ' become confused in the join output'\ .format(self, a0.str_ref_only(), a1.str_ref_only())) self.type = RelType(context.new_tmp(), self.inputs[0].type.attrs + self.inputs[1].type.attrs)
def info(self): yield '{} => {}'.format(symbolic(sym.JOIN), self.type) if self.cond is not None: yield '|' + self.cond.info() elif len(self.pairs) == 0: yield '|inferred: cross product with no join condition' else: for i0, i1 in self.pairs: yield '|inferred: {}[0.{}] = {}[1.{}]'\ .format(self.inputs[0].type.attrs[i0].str_ref_only(), i0, self.inputs[1].type.attrs[i1].str_ref_only(), i1) for i, line in enumerate(self.inputs[0].info()): yield ('\\_' if i == 0 else '| ') + line for i, line in enumerate(self.inputs[1].info()): yield ('\\_' if i == 0 else ' ') + line
def info(self): yield lreplace(str(self), literal(sym.SOURCE), symbolic(sym.SOURCE))
def info(self): yield lreplace(str(self), literal(sym.CLEAR), symbolic(sym.CLEAR))
def info(self): yield symbolic(self.cmd)
def info(self): yield '{} => {}'.format(symbolic(self.op()), self.type) for i, line in enumerate(self.inputs[0].info()): yield ('\\_' if i == 0 else '| ') + line for i, line in enumerate(self.inputs[1].info()): yield ('\\_' if i == 0 else ' ') + line
def info(self): yield '{} => {}'.format(symbolic(sym.SELECT), self.type) yield '|' + self.cond.info() for i, line in enumerate(self.inputs[0].info()): yield ('\\_' if i == 0 else ' ') + line
def info(self): yield '{} => {}'.format(symbolic(sym.PROJECT), self.type) for attr in self.attrs: yield '|' + attr.info() for i, line in enumerate(self.inputs[0].info()): yield ('\\_' if i == 0 else ' ') + line
def info(self): yield symbolic(sym.SQLEXEC) + ': ' + self.sql