public override Resultset Get(QueryContext queryContext, object[] parameters) { if (ChildNodes.Count != 2) throw new InvalidOperationException(); Resultset rs1 = null; Resultset rs2 = null; Iterator.Invoke(new Action[] { () => rs1 = ChildNodes[0].Get(queryContext, parameters), () => rs2 = ChildNodes[1].Get(queryContext, parameters) }); if (!rs1.RowType.RowTypeEquals(rs2.RowType)) throw new ESQLException(Properties.Resources.IncorrectSubqueries); RowType.TypeInfo[] typeInfo = new RowType.TypeInfo[rs1.RowType.Fields.Length]; for (int k = 0; k < typeInfo.Length; k++) if (_type == ConnectorType.ComplexUnion) typeInfo[k] = rs1.RowType.Fields[k]; else typeInfo[k] = new RowType.TypeInfo(k, rs1.RowType.Fields[k], rs2.RowType.Fields[k]); DemandProcessingContext context; if (_type == ConnectorType.Union && _allTag) { context = new DataConcateContext(rs1, rs2); return new Resultset(new RowType(typeInfo), context); } else { if (_allTag) throw new NotImplementedException(); Resultset rs = new Resultset(new RowType(typeInfo), null); IEqualityComparer<Row> comp; if (_type == ConnectorType.ComplexUnion) comp = new RowEqualityComplexComparer(); else comp = new RowEqualityComparer(); HashSet<Row> set1 = new HashSet<Row>(comp); HashSet<Row> set2 = new HashSet<Row>(comp); Iterator.Invoke(new Action[] { () => { while (rs1.Begin != null) set1.Add(rs1.Dequeue()); }, () => { while (rs2.Begin != null) set2.Add(rs2.Dequeue()); }}); switch (_type) { case ConnectorType.Union: case ConnectorType.ComplexUnion: set1.UnionWith(set2); break; case ConnectorType.Except: set1.ExceptWith(set2); break; case ConnectorType.Intersect: set1.IntersectWith(set2); break; } foreach (Row row in set1) rs.Enqueue(row); return rs; } }
public override Resultset Get(QueryContext queryContext, object[] parameters) { // Prepare bindings Resultset source = ChildNodes[0].Get(queryContext, parameters); List<ColumnBinding> bindings = new List<ColumnBinding>(); ExpressionTransformer transformer = new ExpressionTransformer(bindings); foreach (RowType.TypeInfo ti in source.RowType.Fields) foreach (RowType.TypeInfo nested_ti in ti.NestedType.Fields) if (!nested_ti.IsHidden && nested_ti.IsNatural) { ColumnBinding b = new ColumnBinding(); b.typecode = Type.GetTypeCode(nested_ti.DataType); b.rnum = ti.Ordinal; b.TableName = ti.Name; b.Name = nested_ti.Name; b.fieldType = nested_ti; b.natural = nested_ti.IsNatural; b.container = nested_ti.IsContainer; b.caseSensitive = nested_ti.IsCaseSensitive; b.data = new SymbolLink(nested_ti.DataType); bindings.Add(b); if (nested_ti.IsContainer) transformer.NeedTransform = true; } foreach (RowType.TypeInfo ti in source.RowType.Fields) foreach (RowType.TypeInfo nested_ti in ti.NestedType.Fields) if (!nested_ti.IsHidden && !nested_ti.IsNatural) { ColumnBinding b = new ColumnBinding(); b.typecode = Type.GetTypeCode(nested_ti.DataType); b.rnum = ti.Ordinal; b.TableName = ti.Name; b.Name = nested_ti.Name; b.fieldType = nested_ti; b.natural = nested_ti.IsNatural; b.container = nested_ti.IsContainer; b.caseSensitive = nested_ti.IsCaseSensitive; b.data = new SymbolLink(nested_ti.DataType); bindings.Add(b); if (nested_ti.IsContainer) transformer.NeedTransform = true; } // Expand columns. // On this step we transform select table.* and select * to select field1,... List<Column> columns = new List<Column>(); if (_targets == null) // Select fields from all selected tables { foreach (ColumnBinding b in bindings) columns.Add(new Column(ATOM.Create(null, new string[] { b.TableName, b.Name }, false))); } else foreach (Column col in _targets) { if (Lisp.IsFunctor(col.Expr, Table)) // Select fields from specified table { bool found = false; String name = (String)Lisp.Second(col.Expr); var tableBindings = from b in bindings where b.TableName == name select b; foreach (ColumnBinding b in tableBindings) { columns.Add(new Column(ATOM.Create(null, new string[] { b.TableName, b.Name }, false))); found = true; } if (!found) throw new ESQLException(Properties.Resources.InvalidIdentifier, name); } else // Select expression specified if (transformer.NeedTransform) { Column c = new Column(); c.Alias = col.Alias; c.Expr = transformer.Process(col.Expr); columns.Add(c); } else columns.Add(col); } // Create demand context FunctionLink[] compiledBody = new FunctionLink[columns.Count]; SelectorResolver resolver = new SelectorResolver(new Binder(bindings)); SelectorContext context = new SelectorContext(this, _distinct, columns.ToArray(), resolver, source, queryContext, parameters, compiledBody); // Create columns type info and generate unique column names by field name and alias RowType.TypeInfo[] fields = new RowType.TypeInfo[columns.Count]; List<String> fieldNames = new List<string>(); int p = 1; for (int k = 0; k < fields.Length; k++) { String name; RowType.TypeInfo fieldType = null; object expr = columns[k].Expr; compiledBody[k] = new FunctionLink(); Type resType = context.LispExecutive.Compile(null, expr, compiledBody[k]); if (Lisp.IsAtom(expr)) { ColumnBinding b = resolver.GetBinding(expr); if (b != null) fieldType = b.fieldType; } else if (Lisp.IsNode(expr) && expr is String) { fieldType = new RowType.TypeInfo(null, typeof(String), TypeConverter.GetValueSize(expr)); } else if (Lisp.IsFunctor(expr, ID.ParamRef)) { object value = parameters[(int)Lisp.Arg1(expr)]; fieldType = new RowType.TypeInfo(null, value.GetType(), TypeConverter.GetValueSize(value)); } else if (Lisp.IsFunctor(expr, ID.ToString)) { if (Lisp.Length(expr) == 3) fieldType = new RowType.TypeInfo(null, typeof(String), (int)Lisp.Arg2(expr)); else fieldType = new RowType.TypeInfo(null, typeof(String), 0); } else if (Lisp.IsFunctor(expr, ID.ToInt16)) fieldType = new RowType.TypeInfo(null, typeof(Int16), 0); else if (Lisp.IsFunctor(expr, ID.ToInt32)) fieldType = new RowType.TypeInfo(null, typeof(Int32), 0); else if (Lisp.IsFunctor(expr, ID.ToInt64)) fieldType = new RowType.TypeInfo(null, typeof(Int64), 0); else if (Lisp.IsFunctor(expr, ID.ToSingle)) fieldType = new RowType.TypeInfo(null, typeof(Single), 0); else if (Lisp.IsFunctor(expr, ID.ToDouble)) fieldType = new RowType.TypeInfo(null, typeof(Double), 0); else if (Lisp.IsFunctor(expr, ID.ToDecimal)) fieldType = new RowType.TypeInfo(null, typeof(Decimal), 0); else if (Lisp.IsFunctor(expr, ID.ToDateTime)) fieldType = new RowType.TypeInfo(null, typeof(DateTime), 0); else fieldType = new RowType.TypeInfo(null, resType, 0); if (!String.IsNullOrEmpty(columns[k].Alias)) name = columns[k].Alias; else if (fieldType.Name == null) name = String.Format("Expr{0}", p++); else name = fieldType.Name; fields[k] = new RowType.TypeInfo(k, Util.CreateUniqueName(fieldNames, name), fieldType); } ScanDynatableAccessors(ChildNodes[0], resolver); return new Resultset(new RowType(fields), context); }