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 validateSubtree(self, context: StatementContext): self.inputs[0].validateSubtree(context) self.cond.validateSubtree(context, self) if self.cond.type != ValType.BOOLEAN: raise self.validationError('selection condition {} has type {}; boolean expected'\ .format(self.cond, self.cond.type.value)) self.type = RelType(context.new_tmp(), self.inputs[0].type.attrs)
def validateSubtree(self, context: StatementContext): self.inputs[0].validateSubtree(context) if self.attrnames is not None: if len(self.attrnames) != len(self.inputs[0].type.attrs): raise self.validationError('renaming {} attribute(s) but the input has {}'\ .format(len(self.attrnames), len(self.inputs[0].type.attrs))) if len(self.attrnames) != len(set(self.attrnames)): logger.warning('{}: duplicate attribute names when renaming: {}'\ .format(self, ', '.join(self.attrnames))) else: for a1, a2 in itertools.combinations(self.inputs[0].type.attrs, 2): if a1.name == a2.name and not a1.can_be_confused_with(a2): logger.warning('{}: attributes {} and {} become confused after renaming'\ .format(self, a1.str_ref_only(), a2.str_ref_only())) attrspecs = list() if self.attrnames is not None: for name, attrspec in zip(self.attrnames, self.inputs[0].type.attrs): attrspecs.append(AttrSpec(self.relname, name, attrspec.type)) else: for attrspec in self.inputs[0].type.attrs: attrspecs.append( AttrSpec(self.relname, attrspec.name, attrspec.type)) self.type = RelType(self.inputs[0].type.tmp, attrspecs) # don't create a new temp relation
def validateSubtree(self, context: StatementContext): self.inputs[0].validateSubtree(context) self.inputs[1].validateSubtree(context) 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 cross product 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 validateSubtree(self, context: StatementContext): # first check if this is a table in dbms: if context.db.table_exists(self.rel): attrspecs = [AttrSpec(self.rel, attr, type)\ for attr, type in context.db.describe(self.rel)] self.type = RelType(context.new_tmp(), attrspecs) self.view = None return # then check if this is a view defined in this session: view_def = context.views.raw_def(self.rel) if view_def is not None: self.view = RelExpr.from_view_def(view_def) self.view.validateSubtree(context) attrspecs = [AttrSpec(self.rel, attrspec.name, attrspec.type)\ for attrspec in self.view.type.attrs] self.type = RelType(self.view.type.tmp, attrspecs) # don't create a new temp relation return # reference is not found: raise self.validationError('relation {} does not exist'.format(self.rel))
def validateSubtree(self, context: StatementContext): self.inputs[0].validateSubtree(context) output_attrspecs = list() for attr in self.attrs: attr.validateSubtree(context, self) if isinstance(attr, AttrRef): _, aidx = attr.internal_ref output_attrspecs.append(self.inputs[0].type.attrs[aidx]) else: output_attrspecs.append(AttrSpec(None, None, attr.type)) self.type = RelType(context.new_tmp(), output_attrspecs)
def validateSubtree(self, context: StatementContext): self.inputs[0].validateSubtree(context) self.inputs[1].validateSubtree(context) if len(self.inputs[0].type.attrs) != len(self.inputs[1].type.attrs): raise self.validationError('input relations to a set operation' ' do not have the same number of attributes') for i, (a0, a1) in enumerate(zip(self.inputs[0].type.attrs, self.inputs[1].type.attrs)): if a0.type != a1.type: raise self.validationError('input attributes at position {} have' ' different types: {} vs. {}'.format(i, a0, a1)) if a0.name != a1.name: logger.warning('{}: input attributes at position {} have' ' different names: {} vs. {}'.format(self, i, a0.str_ref_only(), a1.str_ref_only())) self.type = RelType(context.new_tmp(), self.inputs[0].type.attrs)
def validateSubtree(self, context: StatementContext): self.inputs[0].validateSubtree(context) output_attrspecs = list() for groupby in self.groupbys: groupby.validateSubtree(context, self) if isinstance(groupby, AttrRef): _, aidx = groupby.internal_ref output_attrspecs.append(self.inputs[0].type.attrs[aidx]) else: output_attrspecs.append(AttrSpec(None, None, groupby.type)) for aggr in self.aggrs: aggr.validateSubtree(context, self, allow_aggr=True) aggr.checkSubtreeGroupInvariant(self) if isinstance(aggr, AttrRef): # rare, but techincally possible _, aidx = groupby.internal_ref output_attrspecs.append(self.inputs[0].type.attrs[aidx]) else: output_attrspecs.append(AttrSpec(None, None, aggr.type)) self.type = RelType(context.new_tmp(), output_attrspecs)