public override void Bind(BindContext context) { Debug.Assert(IsLeaf()); Debug.Assert(tabRef_ is null); Debug.Assert(tabName_ == tableName_()); // if table name is not given, search through all tablerefs isParameter_ = false; tabRef_ = context.GetTableRef(tabName_, colName_); // we can't find the column in current context, so it could an outer reference if (tabRef_ is null) { // can't find in my current context, try my ancestors levels up: order is important // as we are matching naming with the order closest first // ... from A ... ( from A where exists (... from B where b1 > a.a1)) // so a.a1 matches the inner side A. // BindContext parent = context; while ((parent = parent.parent_) != null) { tabRef_ = parent.GetTableRef(tabName_, colName_); if (tabRef_ != null) { // we are actually switch the context to parent, whichTab_ is not right ... isParameter_ = true; tabRef_.colRefedBySubq_.Add(this); // mark myself a correlated query and remember whom I am correlated to var mystmt = context.stmt_ as SelectStmt; mystmt.isCorrelated_ = true; mystmt.correlatedWhich_.Add(parent.stmt_ as SelectStmt); context = parent; break; } } if (tabRef_ is null) { throw new SemanticAnalyzeException($"can't bind column '{colName_}' to table"); } } // we have identified the tableRef this belongs to, make sure outputName not conflicting // Eg. select c1 as c2, ... from c if (!outputName_.Equals(colName_) && tabRef_.LocateColumn(outputName_) != null) { throw new SemanticAnalyzeException($"conflicting output name {outputName_} is not allowed"); } Debug.Assert(tabRef_ != null); if (!isParameter_) { Debug.Assert(tableRefs_.Count == 0); tableRefs_.Add(tabRef_); } // FIXME: we shall not decide ordinal_ so early but if not, hard to handle outerref ordinal_ = context.ColumnOrdinal(tabRef_.alias_, colName_, out ColumnType type); type_ = type; markBounded(); }