1 //--------------------------------------------------------------------- 2 // <copyright file="Command.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 // 6 // @owner Microsoft 7 // @backupOwner Microsoft 8 //--------------------------------------------------------------------- 9 10 using System.Collections.Generic; 11 using System.Data.Common; 12 using System.Data.Metadata.Edm; 13 using System.Data.Query.PlanCompiler; 14 using System.Diagnostics; 15 using System.Linq; 16 17 namespace System.Data.Query.InternalTrees 18 { 19 /// <summary> 20 /// The Command object encapsulates all information relating to a single command. 21 /// It includes the expression tree in question, as well as the parameters to the 22 /// command. 23 /// Additionally, the Command class serves as a factory for building up different 24 /// nodes and Ops. Every node in the tree has a unique id, and this is enforced by 25 /// the node factory methods 26 /// </summary> 27 internal class Command 28 { 29 #region private state 30 private Dictionary<string, ParameterVar> m_parameterMap; 31 private List<Var> m_vars; 32 private List<Table> m_tables; 33 private Node m_root; 34 private MetadataWorkspace m_metadataWorkspace; 35 private TypeUsage m_boolType; 36 private TypeUsage m_intType; 37 private TypeUsage m_stringType; 38 private ConstantPredicateOp m_trueOp; 39 private ConstantPredicateOp m_falseOp; 40 private NodeInfoVisitor m_nodeInfoVisitor; 41 private PlanCompiler.KeyPullup m_keyPullupVisitor; 42 private int m_nextNodeId; 43 private int m_nextBranchDiscriminatorValue = 1000; 44 45 private bool m_disableVarVecEnumCaching; 46 private Stack<VarVec.VarVecEnumerator> m_freeVarVecEnumerators; 47 private Stack<VarVec> m_freeVarVecs; 48 49 50 // set of referenced rel properties in this query 51 private HashSet<RelProperty> m_referencedRelProperties; 52 #endregion 53 54 #region constructors 55 /// <summary> 56 /// Creates a new command 57 /// </summary> Command(MetadataWorkspace metadataWorkspace)58 internal Command(MetadataWorkspace metadataWorkspace) 59 { 60 m_parameterMap = new Dictionary<string, ParameterVar>(); 61 m_vars = new List<Var>(); 62 m_tables = new List<Table>(); 63 m_metadataWorkspace = metadataWorkspace; 64 if(!TryGetPrimitiveType(PrimitiveTypeKind.Boolean, out m_boolType)) 65 { 66 throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderBooleanType); 67 } 68 if (!TryGetPrimitiveType(PrimitiveTypeKind.Int32, out m_intType)) 69 { 70 throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderIntegerType); 71 } 72 if (!TryGetPrimitiveType(PrimitiveTypeKind.String, out m_stringType)) 73 { 74 throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.Cqt_General_NoProviderStringType); 75 } 76 m_trueOp = new ConstantPredicateOp(m_boolType, true); 77 m_falseOp = new ConstantPredicateOp(m_boolType, false); 78 m_nodeInfoVisitor = new NodeInfoVisitor(this); 79 m_keyPullupVisitor = new PlanCompiler.KeyPullup(this); 80 81 // FreeLists 82 m_freeVarVecEnumerators = new Stack<VarVec.VarVecEnumerator>(); 83 m_freeVarVecs = new Stack<VarVec>(); 84 85 m_referencedRelProperties = new HashSet<RelProperty>(); 86 } 87 #endregion 88 89 #region public methods 90 /// <summary> 91 /// Gets the metadata workspace associated with this command 92 /// </summary> 93 internal MetadataWorkspace MetadataWorkspace { get { return m_metadataWorkspace; } } 94 95 /// <summary> 96 /// Gets/sets the root node of the query 97 /// </summary> 98 internal Node Root { get { return m_root; } set { m_root = value; } } 99 DisableVarVecEnumCaching()100 internal void DisableVarVecEnumCaching() { m_disableVarVecEnumCaching = true; } 101 102 /// <summary> 103 /// Returns the next value for a UnionAll BranchDiscriminator. 104 /// </summary> 105 internal int NextBranchDiscriminatorValue { get { return m_nextBranchDiscriminatorValue++; } } 106 107 /// <summary> 108 /// Returns the next value for a node id, without incrementing it. 109 /// </summary> 110 internal int NextNodeId { get { return m_nextNodeId; } } 111 112 #region Metadata Helpers 113 /// <summary> 114 /// Helper routine to get the metadata representation for the bool type 115 /// </summary> 116 internal TypeUsage BooleanType 117 { 118 get { return m_boolType; } 119 } 120 121 /// <summary> 122 /// Helper routine to get the metadata representation of the int type 123 /// </summary> 124 internal TypeUsage IntegerType 125 { 126 get { return m_intType; } 127 } 128 129 /// <summary> 130 /// Helper routine to get the metadata representation of the string type 131 /// </summary> 132 internal TypeUsage StringType 133 { 134 get { return m_stringType; } 135 } 136 137 /// <summary> 138 /// Get the primitive type by primitive type kind 139 /// </summary> 140 /// <param name="modelType">EdmMetadata.PrimitiveTypeKind of the primitive type</param> 141 /// <param name="type">A TypeUsage that represents the specified primitive type</param> 142 /// <returns><c>True</c> if the specified primitive type could be retrieved; otherwise <c>false</c>.</returns> TryGetPrimitiveType(PrimitiveTypeKind modelType, out TypeUsage type)143 private bool TryGetPrimitiveType(PrimitiveTypeKind modelType, out TypeUsage type) 144 { 145 type = null; 146 147 if (modelType == PrimitiveTypeKind.String) 148 { 149 type = TypeUsage.CreateStringTypeUsage(m_metadataWorkspace.GetModelPrimitiveType(modelType), 150 false /*unicode*/, 151 false /*fixed*/); 152 } 153 else 154 { 155 type = m_metadataWorkspace.GetCanonicalModelTypeUsage(modelType); 156 } 157 158 return (null != type); 159 } 160 #endregion 161 162 #region VarVec Creation 163 /// <summary> 164 /// VarVec constructor 165 /// </summary> 166 /// <returns>A new, empty, VarVec</returns> CreateVarVec()167 internal VarVec CreateVarVec() 168 { 169 VarVec vec; 170 if (m_freeVarVecs.Count == 0) 171 { 172 vec = new VarVec(this); 173 } 174 else 175 { 176 vec = m_freeVarVecs.Pop(); 177 vec.Clear(); 178 } 179 return vec; 180 } 181 182 /// <summary> 183 /// Create a VarVec with a single Var 184 /// </summary> 185 /// <param name="v"></param> 186 /// <returns></returns> CreateVarVec(Var v)187 internal VarVec CreateVarVec(Var v) 188 { 189 VarVec varset = CreateVarVec(); 190 varset.Set(v); 191 return varset; 192 } 193 194 /// <summary> 195 /// Create a VarVec with the set of specified vars 196 /// </summary> 197 /// <param name="v"></param> 198 /// <returns></returns> CreateVarVec(IEnumerable<Var> v)199 internal VarVec CreateVarVec(IEnumerable<Var> v) 200 { 201 VarVec vec = CreateVarVec(); 202 vec.InitFrom(v); 203 return vec; 204 } 205 206 /// <summary> 207 /// Create a new VarVec from the input VarVec 208 /// </summary> 209 /// <param name="v"></param> 210 /// <returns></returns> CreateVarVec(VarVec v)211 internal VarVec CreateVarVec(VarVec v) 212 { 213 VarVec vec = CreateVarVec(); 214 vec.InitFrom(v); 215 return vec; 216 } 217 218 /// <summary> 219 /// Release a VarVec to the freelist 220 /// </summary> 221 /// <param name="vec"></param> ReleaseVarVec(VarVec vec)222 internal void ReleaseVarVec(VarVec vec) 223 { 224 m_freeVarVecs.Push(vec); 225 } 226 #endregion 227 228 #region VarVecEnumerator 229 /// <summary> 230 /// Create a new enumerator for a VarVec; use a free one if its 231 /// available; otherwise, create a new one 232 /// </summary> 233 /// <param name="vec"></param> 234 /// <returns></returns> GetVarVecEnumerator(VarVec vec)235 internal VarVec.VarVecEnumerator GetVarVecEnumerator(VarVec vec) 236 { 237 VarVec.VarVecEnumerator enumerator; 238 239 if (m_disableVarVecEnumCaching || 240 m_freeVarVecEnumerators.Count == 0) 241 { 242 enumerator = new VarVec.VarVecEnumerator(vec); 243 } 244 else 245 { 246 enumerator = m_freeVarVecEnumerators.Pop(); 247 enumerator.Init(vec); 248 } 249 return enumerator; 250 } 251 252 /// <summary> 253 /// Release an enumerator; keep it in a local stack for future use 254 /// </summary> 255 /// <param name="enumerator"></param> ReleaseVarVecEnumerator(VarVec.VarVecEnumerator enumerator)256 internal void ReleaseVarVecEnumerator(VarVec.VarVecEnumerator enumerator) 257 { 258 if (!m_disableVarVecEnumCaching) 259 { 260 m_freeVarVecEnumerators.Push(enumerator); 261 } 262 } 263 #endregion 264 265 #region VarList 266 /// <summary> 267 /// Create an ordered list of Vars - initially empty 268 /// </summary> 269 /// <returns></returns> CreateVarList()270 internal static VarList CreateVarList() 271 { 272 return new VarList(); 273 } 274 275 /// <summary> 276 /// Create an ordered list of Vars 277 /// </summary> 278 /// <param name="vars"></param> 279 /// <returns></returns> CreateVarList(IEnumerable<Var> vars)280 internal static VarList CreateVarList(IEnumerable<Var> vars) 281 { 282 return new VarList(vars); 283 } 284 #endregion 285 286 #region VarMap CreateVarMap()287 internal VarMap CreateVarMap() 288 { 289 return new VarMap(); 290 } 291 292 #endregion 293 294 #region Table Helpers 295 NewTableId()296 private int NewTableId() 297 { 298 return m_tables.Count; 299 } 300 301 302 /// <summary> 303 /// Create a table whose element type is "elementType" 304 /// </summary> 305 /// <param name="elementType">type of each element (row) of the table</param> 306 /// <returns>a table definition object</returns> CreateTableDefinition(TypeUsage elementType)307 internal static TableMD CreateTableDefinition(TypeUsage elementType) 308 { 309 return new TableMD(elementType, null); 310 } 311 312 /// <summary> 313 /// Creates a new table definition based on an extent. The element type 314 /// of the extent manifests as the single column of the table 315 /// </summary> 316 /// <param name="extent">the metadata extent</param> 317 /// <returns>A new TableMD instance based on the extent</returns> CreateTableDefinition(EntitySetBase extent)318 internal static TableMD CreateTableDefinition(EntitySetBase extent) 319 { 320 return new TableMD(TypeUsage.Create(extent.ElementType), extent); 321 } 322 323 /// <summary> 324 /// Create a "flat" table definition object (ie) the table has one column 325 /// for each property of the specified row type 326 /// </summary> 327 /// <param name="type">the shape of each row of the table</param> 328 /// <returns>the table definition</returns> CreateFlatTableDefinition(RowType type)329 internal TableMD CreateFlatTableDefinition(RowType type) 330 { 331 return CreateFlatTableDefinition(type.Properties, new List<EdmMember>(), null); 332 } 333 334 /// <summary> 335 /// Create a "flat" table defintion. The table has one column for each property 336 /// specified, and the key columns of the table are those specified in the 337 /// keyMembers parameter 338 /// </summary> 339 /// <param name="properties">list of columns for the table</param> 340 /// <param name="keyMembers">the key columns (if any)</param> 341 /// <param name="entitySet">(OPTIONAL) entityset corresponding to this table</param> 342 /// <returns></returns> CreateFlatTableDefinition(IEnumerable<EdmProperty> properties, IEnumerable<EdmMember> keyMembers, EntitySetBase entitySet)343 internal TableMD CreateFlatTableDefinition(IEnumerable<EdmProperty> properties, IEnumerable<EdmMember> keyMembers, EntitySetBase entitySet) 344 { 345 return new TableMD(properties, keyMembers, entitySet); 346 } 347 348 /// <summary> 349 /// Creates a new table instance 350 /// </summary> 351 /// <param name="tableMetadata">table metadata</param> 352 /// <returns>A new Table instance with columns as defined in the specified metadata</returns> CreateTableInstance(TableMD tableMetadata)353 internal Table CreateTableInstance(TableMD tableMetadata) 354 { 355 Table t = new Table(this, tableMetadata, NewTableId()); 356 m_tables.Add(t); 357 return t; 358 } 359 360 #endregion 361 362 #region Var Access 363 364 /// <summary> 365 /// All vars in the query 366 /// </summary> 367 internal IEnumerable<Var> Vars 368 { 369 get { return m_vars.Where(v => v.VarType != VarType.NotValid); } 370 } 371 372 /// <summary> 373 /// Access an existing variable in the query (by its id) 374 /// </summary> 375 /// <param name="id">The ID of the variable to retrieve</param> 376 /// <returns>The variable with the specified ID</returns> GetVar(int id)377 internal Var GetVar(int id) 378 { 379 Debug.Assert(m_vars[id].VarType != VarType.NotValid, "The var has been replaced by a different var and is no longer valid."); 380 381 return m_vars[id]; 382 } 383 384 /// <summary> 385 /// Gets the ParameterVar that corresponds to a given named parameter 386 /// </summary> 387 /// <param name="paramName">The name of the parameter for which to retrieve the ParameterVar</param> 388 /// <returns>The ParameterVar that corresponds to the specified parameter</returns> GetParameter(string paramName)389 internal ParameterVar GetParameter(string paramName) 390 { 391 return m_parameterMap[paramName]; 392 } 393 394 #endregion 395 396 #region Var Creation 397 NewVarId()398 private int NewVarId() 399 { 400 return m_vars.Count; 401 } 402 403 /// <summary> 404 /// Creates a variable for a parameter in the query 405 /// </summary> 406 /// <param name="parameterName">The name of the parameter for which to create the var</param> 407 /// <param name="parameterType">The type of the parameter, and therefore the new var</param> 408 /// <returns>A new ParameterVar instance with the specified name and type</returns> CreateParameterVar(string parameterName, TypeUsage parameterType)409 internal ParameterVar CreateParameterVar(string parameterName, 410 TypeUsage parameterType) 411 { 412 if (m_parameterMap.ContainsKey(parameterName)) 413 throw new Exception("duplicate parameter name: " + parameterName); 414 ParameterVar v = new ParameterVar(NewVarId(), parameterType, parameterName); 415 m_vars.Add(v); 416 m_parameterMap[parameterName] = v; 417 return v; 418 } 419 420 /// <summary> 421 /// Creates a variable for the given parameter variable and replaces it in parameter map. 422 /// </summary> 423 /// <param name="oldVar">Parameter variable that needs to replaced.</param> 424 /// <param name="generateReplacementType">Delegate that generates the replacement parameter's type.</param> 425 /// <returns>A new ParameterVar instance created of <paramref name="oldVar"/>.</returns> 426 /// <remarks> 427 /// This method should be used only to replace external enum or strong spatial parameters with a counterpart whose 428 /// type is the underlying type of the enum type, or the union type contating the strong spatial type of the <paramref name="oldVar"/>. 429 /// The operation invalidates the <paramref name="oldVar"/>. After the operation has completed 430 /// the <paramref name="oldVar"/>) is invalidated internally and should no longer be used. 431 /// </remarks>Func< ReplaceParameterVar(ParameterVar oldVar, Func<TypeUsage, TypeUsage> generateReplacementType)432 private ParameterVar ReplaceParameterVar(ParameterVar oldVar, Func<TypeUsage, TypeUsage> generateReplacementType) 433 { 434 Debug.Assert(oldVar != null, "oldVar != null"); 435 Debug.Assert(m_vars.Contains(oldVar)); 436 ParameterVar v = new ParameterVar(NewVarId(), generateReplacementType(oldVar.Type), oldVar.ParameterName); 437 m_parameterMap[oldVar.ParameterName] = v; 438 m_vars.Add(v); 439 return v; 440 } 441 442 /// <summary> 443 /// Creates a variable for the given enum parameter variable and replaces it in parameter map. 444 /// </summary> 445 /// <param name="oldVar">Enum parameter variable that needs to replaced.</param> 446 /// <returns>A new ParameterVar instance created of <paramref name="oldVar"/>.</returns> 447 /// <remarks> 448 /// This method should be used only to replace external enum parameter with a counterpart whose 449 /// type is the underlying type of the enum type of the <paramref name="oldVar"/>. 450 /// The operation invalidates the <paramref name="oldVar"/>. After the operation has completed 451 /// the <paramref name="oldVar"/>) is invalidated internally and should no longer be used. 452 /// </remarks> ReplaceEnumParameterVar(ParameterVar oldVar)453 internal ParameterVar ReplaceEnumParameterVar(ParameterVar oldVar) 454 { 455 return ReplaceParameterVar(oldVar, t => TypeHelpers.CreateEnumUnderlyingTypeUsage(t)); 456 } 457 458 /// <summary> 459 /// Creates a variable for the given spatial parameter variable and replaces it in parameter map. 460 /// </summary> 461 /// <param name="oldVar">Spatial parameter variable that needs to replaced.</param> 462 /// <returns>A new ParameterVar instance created of <paramref name="oldVar"/>.</returns> 463 /// <remarks> 464 /// This method should be used only to replace external strong spatial parameter with a counterpart whose 465 /// type is the appropriate union type for <paramref name="oldVar"/>. 466 /// The operation invalidates the <paramref name="oldVar"/>. After the operation has completed 467 /// the <paramref name="oldVar"/>) is invalidated internally and should no longer be used. 468 /// </remarks> ReplaceStrongSpatialParameterVar(ParameterVar oldVar)469 internal ParameterVar ReplaceStrongSpatialParameterVar(ParameterVar oldVar) 470 { 471 return ReplaceParameterVar(oldVar, t => TypeHelpers.CreateSpatialUnionTypeUsage(t)); 472 } 473 474 475 /// <summary> 476 /// Creates a new var for a table column 477 /// </summary> 478 /// <param name="table">The table instance that produces the column</param> 479 /// <param name="columnMD">column metadata</param> 480 /// <returns>A new ColumnVar instance that references the specified column in the given table</returns> CreateColumnVar(Table table, ColumnMD columnMD)481 internal ColumnVar CreateColumnVar(Table table, ColumnMD columnMD) 482 { 483 // create a new column var now 484 ColumnVar c = new ColumnVar(NewVarId(), table, columnMD); 485 table.Columns.Add(c); 486 m_vars.Add(c); 487 return c; 488 } 489 490 /// <summary> 491 /// Creates a computed var (ie) a variable that is computed by an expression 492 /// </summary> 493 /// <param name="type">The type of the result produced by the expression that defines the variable</param> 494 /// <returns>A new ComputedVar instance with the specified result type</returns> CreateComputedVar(TypeUsage type)495 internal ComputedVar CreateComputedVar(TypeUsage type) 496 { 497 ComputedVar v = new ComputedVar(NewVarId(), type); 498 m_vars.Add(v); 499 return v; 500 } 501 502 /// <summary> 503 /// Creates a SetOp Var of 504 /// </summary> 505 /// <param name="type">Datatype of the Var</param> 506 /// <returns>A new SetOp Var with the specified result type</returns> CreateSetOpVar(TypeUsage type)507 internal SetOpVar CreateSetOpVar(TypeUsage type) 508 { 509 SetOpVar v = new SetOpVar(NewVarId(), type); 510 m_vars.Add(v); 511 return v; 512 } 513 514 #endregion 515 516 #region Node Creation 517 // 518 // The routines below help in node construction. All command tree nodes must go 519 // through these routines. These routines help to stamp each node with a unique 520 // id (the id is very helpful for debugging) 521 // 522 523 /// <summary> 524 /// Creates a Node with zero children 525 /// </summary> 526 /// <param name="op">The operator that the Node should reference</param> 527 /// <returns>A new Node with zero children that references the specified Op</returns> CreateNode(Op op)528 internal Node CreateNode(Op op) 529 { 530 return this.CreateNode(op, new List<Node>()); 531 } 532 533 /// <summary> 534 /// Creates a node with a single child Node 535 /// </summary> 536 /// <param name="op">The operator that the Node should reference</param> 537 /// <param name="arg1">The single child Node</param> 538 /// <returns>A new Node with the specified child Node, that references the specified Op</returns> CreateNode(Op op, Node arg1)539 internal Node CreateNode(Op op, Node arg1) 540 { 541 List<Node> l = new List<Node>(); 542 l.Add(arg1); 543 return this.CreateNode(op, l); 544 } 545 546 /// <summary> 547 /// Creates a node with two child Nodes 548 /// </summary> 549 /// <param name="op">The operator that the Node should reference</param> 550 /// <param name="arg1">The first child Node</param> 551 /// <param name="arg2">the second child Node</param> 552 /// <returns>A new Node with the specified child Nodes, that references the specified Op</returns> CreateNode(Op op, Node arg1, Node arg2)553 internal Node CreateNode(Op op, Node arg1, Node arg2) 554 { 555 List<Node> l = new List<Node>(); 556 l.Add(arg1); l.Add(arg2); 557 return this.CreateNode(op, l); 558 } 559 560 /// <summary> 561 /// Creates a node with 3 child Nodes 562 /// </summary> 563 /// <param name="op">The operator that the Node should reference</param> 564 /// <param name="arg1">The first child Node</param> 565 /// <param name="arg2">The second child Node</param> 566 /// <param name="arg3">The third child Node</param> 567 /// <returns>A new Node with the specified child Nodes, that references the specified Op</returns> CreateNode(Op op, Node arg1, Node arg2, Node arg3)568 internal Node CreateNode(Op op, Node arg1, Node arg2, Node arg3) 569 { 570 List<Node> l = new List<Node>(); 571 l.Add(arg1); l.Add(arg2); l.Add(arg3); 572 return this.CreateNode(op, l); 573 } 574 575 /// <summary> 576 /// Create a Node with the specified list of child Nodes 577 /// </summary> 578 /// <param name="op">The operator that the Node should reference</param> 579 /// <param name="args">The list of child Nodes</param> 580 /// <returns>A new Node with the specified child nodes, that references the specified Op</returns> CreateNode(Op op, IList<Node> args)581 internal Node CreateNode(Op op, IList<Node> args) 582 { 583 return new Node(m_nextNodeId++, op, new List<Node>(args)); 584 } 585 586 /// <summary> 587 /// Create a Node with the specified list of child Nodes 588 /// </summary> 589 /// <param name="op">The operator that the Node should reference</param> 590 /// <param name="args">The list of child Nodes</param> 591 /// <returns>A new Node with the specified child nodes, that references the specified Op</returns> CreateNode(Op op, List<Node> args)592 internal Node CreateNode(Op op, List<Node> args) 593 { 594 return new Node(m_nextNodeId++, op, args); 595 } 596 597 #endregion 598 599 #region ScalarOps 600 601 /// <summary> 602 /// Creates a new ConstantOp 603 /// </summary> 604 /// <param name="type">The type of the constant value</param> 605 /// <param name="value">The constant value (may be null)</param> 606 /// <returns>A new ConstantOp with the specified type and value</returns> CreateConstantOp(TypeUsage type, object value)607 internal ConstantBaseOp CreateConstantOp(TypeUsage type, object value) 608 { 609 // create a NullOp if necessary 610 if (value == null) 611 { 612 return new NullOp(type); 613 } 614 // Identify "safe" constants - the only safe ones are boolean (and we should 615 // probably include ints eventually) 616 else if (TypeSemantics.IsBooleanType(type)) 617 { 618 return new InternalConstantOp(type, value); 619 } 620 else 621 { 622 return new ConstantOp(type, value); 623 } 624 } 625 626 /// <summary> 627 /// Create an "internal" constantOp - only for use by the plan compiler to 628 /// represent internally generated constants. 629 /// User constants in the query should never get into this function 630 /// </summary> 631 /// <param name="type">datatype of the constant</param> 632 /// <param name="value">constant value</param> 633 /// <returns>a new "internal" constant op that represents the constant</returns> CreateInternalConstantOp(TypeUsage type, object value)634 internal InternalConstantOp CreateInternalConstantOp(TypeUsage type, object value) 635 { 636 return new InternalConstantOp(type, value); 637 } 638 639 /// <summary> 640 /// An internal constant that serves as a null sentinel, i.e. it is only ever used 641 /// to be checked whether it is null 642 /// </summary> 643 /// <returns></returns> CreateNullSentinelOp()644 internal NullSentinelOp CreateNullSentinelOp() 645 { 646 return new NullSentinelOp(this.IntegerType, 1); 647 } 648 649 /// <summary> 650 /// An "internal" null constant 651 /// </summary> 652 /// <param name="type">datatype of the null constant</param> 653 /// <returns>a new "internal" null constant op</returns> CreateNullOp(TypeUsage type)654 internal NullOp CreateNullOp(TypeUsage type) 655 { 656 return new NullOp(type); 657 } 658 659 /// <summary> 660 /// Create a constant predicateOp 661 /// </summary> 662 /// <param name="value">value of the constant predicate</param> 663 /// <returns></returns> CreateConstantPredicateOp(bool value)664 internal ConstantPredicateOp CreateConstantPredicateOp(bool value) 665 { 666 return value ? m_trueOp : m_falseOp; 667 } 668 669 /// <summary> 670 /// Create a constant predicate with value=true 671 /// </summary> 672 /// <returns></returns> CreateTrueOp()673 internal ConstantPredicateOp CreateTrueOp() 674 { 675 return m_trueOp; 676 } 677 /// <summary> 678 /// Create a constant predicateOp with the value false 679 /// </summary> 680 /// <returns></returns> CreateFalseOp()681 internal ConstantPredicateOp CreateFalseOp() 682 { 683 return m_falseOp; 684 } 685 686 /// <summary> 687 /// Creates a new FunctionOp 688 /// </summary> 689 /// <param name="function">EdmFunction metadata that represents the function that is invoked by the Op</param> 690 /// <returns>A new FunctionOp that references the specified function metadata</returns> CreateFunctionOp(EdmFunction function)691 internal FunctionOp CreateFunctionOp(EdmFunction function) 692 { 693 return new FunctionOp(function); 694 } 695 696 /// <summary> 697 /// Creates a new TreatOp 698 /// </summary> 699 /// <param name="type">Type metadata that specifies the type that the child of the treat node should be treated as</param> 700 /// <returns>A new TreatOp that references the specified type metadata</returns> CreateTreatOp(TypeUsage type)701 internal TreatOp CreateTreatOp(TypeUsage type) 702 { 703 return new TreatOp(type, false); 704 } 705 706 /// <summary> 707 /// Create a "dummy" treatOp (i.e.) we can actually ignore the treatOp. 708 /// </summary> 709 /// <param name="type"></param> 710 /// <returns></returns> CreateFakeTreatOp(TypeUsage type)711 internal TreatOp CreateFakeTreatOp(TypeUsage type) 712 { 713 return new TreatOp(type, true); 714 } 715 716 /// <summary> 717 /// Creates a new IsOfOp, which tests if the argument is of the specified type or a promotable type 718 /// </summary> 719 /// <param name="isOfType">Type metadata that specifies the type with which the type of the argument should be compared</param> 720 /// <returns>A new IsOfOp that references the specified type metadata</returns> CreateIsOfOp(TypeUsage isOfType)721 internal IsOfOp CreateIsOfOp(TypeUsage isOfType) 722 { 723 return new IsOfOp(isOfType, false/*only*/, m_boolType); 724 } 725 /// <summary> 726 /// Creates a new IsOfOp, which tests if the argument is of the specified type (and only the specified type) 727 /// </summary> 728 /// <param name="isOfType">Type metadata that specifies the type with which the type of the argument should be compared</param> 729 /// <returns>A new IsOfOp that references the specified type metadata</returns> CreateIsOfOnlyOp(TypeUsage isOfType)730 internal IsOfOp CreateIsOfOnlyOp(TypeUsage isOfType) 731 { 732 return new IsOfOp(isOfType, true /* "only" */, m_boolType); 733 } 734 735 /// <summary> 736 /// Creates a new CastOp 737 /// </summary> 738 /// <param name="type">Type metadata that represents the type to which the argument should be cast</param> 739 /// <returns>A new CastOp that references the specified type metadata</returns> CreateCastOp(TypeUsage type)740 internal CastOp CreateCastOp(TypeUsage type) 741 { 742 return new CastOp(type); 743 } 744 745 /// <summary> 746 /// Creates a new SoftCastOp and casts the input to the desired type. 747 /// 748 /// The caller is expected to determine if the cast is necessary or not 749 /// </summary> 750 /// <param name="type">Type metadata that represents the type to which the argument should be cast</param> 751 /// <returns>A new CastOp that references the specified type metadata</returns> CreateSoftCastOp(TypeUsage type)752 internal SoftCastOp CreateSoftCastOp(TypeUsage type) 753 { 754 return new SoftCastOp(type); 755 } 756 757 /// <summary> 758 /// Creates a new ComparisonOp of the specified type 759 /// </summary> 760 /// <param name="opType">An OpType that specifies one of the valid comparison OpTypes: EQ, GT, GE, NE, LT, LE</param> 761 /// <returns>A new ComparisonOp of the specified comparison OpType</returns> CreateComparisonOp(OpType opType)762 internal ComparisonOp CreateComparisonOp(OpType opType) 763 { 764 return new ComparisonOp(opType, this.BooleanType); 765 } 766 767 /// <summary> 768 /// Creates a new LikeOp 769 /// </summary> 770 /// <returns>The new LikeOp</returns> CreateLikeOp()771 internal LikeOp CreateLikeOp() 772 { 773 return new LikeOp(this.BooleanType); 774 } 775 776 /// <summary> 777 /// Creates a new ConditionalOp of the specified type 778 /// </summary> 779 /// <param name="opType">An OpType that specifies one of the valid condition operations: And, Or, Not, IsNull</param> 780 /// <returns>A new ConditionalOp with the specified conditional OpType</returns> CreateConditionalOp(OpType opType)781 internal ConditionalOp CreateConditionalOp(OpType opType) 782 { 783 return new ConditionalOp(opType, this.BooleanType); 784 } 785 786 /// <summary> 787 /// Creates a new CaseOp 788 /// </summary> 789 /// <param name="type">The result type of the CaseOp</param> 790 /// <returns>A new CaseOp with the specified result type</returns> CreateCaseOp(TypeUsage type)791 internal CaseOp CreateCaseOp(TypeUsage type) 792 { 793 return new CaseOp(type); 794 } 795 796 /// <summary> 797 /// Creates a new AggregateOp 798 /// </summary> 799 /// <param name="aggFunc">EdmFunction metadata that specifies the aggregate function</param> 800 /// <param name="distinctAgg">Indicates whether or not the aggregate is a distinct aggregate</param> 801 /// <returns>A new AggregateOp with the specified function metadata and distinct property</returns> CreateAggregateOp(EdmFunction aggFunc, bool distinctAgg)802 internal AggregateOp CreateAggregateOp(EdmFunction aggFunc, bool distinctAgg) 803 { 804 return new AggregateOp(aggFunc, distinctAgg); 805 } 806 807 /// <summary> 808 /// Creates a named type constructor 809 /// </summary> 810 /// <param name="type">Type metadata that specifies the type of the instance to construct</param> 811 /// <returns>A new NewInstanceOp with the specified result type</returns> CreateNewInstanceOp(TypeUsage type)812 internal NewInstanceOp CreateNewInstanceOp(TypeUsage type) 813 { 814 return new NewInstanceOp(type); 815 } 816 817 /// <summary> 818 /// Build out a new NewEntityOp constructing the entity <paramref name="type"/> scoped to the <paramref name="entitySet"/>. 819 /// </summary> CreateScopedNewEntityOp(TypeUsage type, List<RelProperty> relProperties, EntitySet entitySet)820 internal NewEntityOp CreateScopedNewEntityOp(TypeUsage type, List<RelProperty> relProperties, EntitySet entitySet) 821 { 822 return new NewEntityOp(type, relProperties, true, entitySet); 823 } 824 825 /// <summary> 826 /// Build out a new NewEntityOp constructing the uscoped entity <paramref name="type"/>. 827 /// </summary> CreateNewEntityOp(TypeUsage type, List<RelProperty> relProperties)828 internal NewEntityOp CreateNewEntityOp(TypeUsage type, List<RelProperty> relProperties) 829 { 830 return new NewEntityOp(type, relProperties, false, null); 831 } 832 833 /// <summary> 834 /// Create a discriminated named type constructor 835 /// </summary> 836 /// <param name="type">Type metadata that specifies the type of the instance to construct</param> 837 /// <param name="discriminatorMap">Mapping information including discriminator values</param> 838 /// <param name="entitySet">the entityset that this instance belongs to</param> 839 /// <param name="relProperties">list of rel properties that have corresponding values</param> 840 /// <returns>A new DiscriminatedNewInstanceOp with the specified result type and discrimination behavior</returns> CreateDiscriminatedNewEntityOp(TypeUsage type, ExplicitDiscriminatorMap discriminatorMap, EntitySet entitySet, List<RelProperty> relProperties)841 internal DiscriminatedNewEntityOp CreateDiscriminatedNewEntityOp(TypeUsage type, ExplicitDiscriminatorMap discriminatorMap, 842 EntitySet entitySet, List<RelProperty> relProperties) 843 { 844 return new DiscriminatedNewEntityOp(type, discriminatorMap, entitySet, relProperties); 845 } 846 847 /// <summary> 848 /// Creates a multiset constructor 849 /// </summary> 850 /// <param name="type">Type metadata that specifies the type of the multiset to construct</param> 851 /// <returns>A new NewMultiSetOp with the specified result type</returns> CreateNewMultisetOp(TypeUsage type)852 internal NewMultisetOp CreateNewMultisetOp(TypeUsage type) 853 { 854 return new NewMultisetOp(type); 855 } 856 857 /// <summary> 858 /// Creates a record constructor 859 /// </summary> 860 /// <param name="type">Type metadata that specifies that record type to construct</param> 861 /// <returns>A new NewRecordOp with the specified result type</returns> CreateNewRecordOp(TypeUsage type)862 internal NewRecordOp CreateNewRecordOp(TypeUsage type) 863 { 864 return new NewRecordOp(type); 865 } 866 867 /// <summary> 868 /// Creates a record constructor 869 /// </summary> 870 /// <param name="type">Type metadata that specifies that record type to construct</param> 871 /// <returns>A new NewRecordOp with the specified result type</returns> CreateNewRecordOp(RowType type)872 internal NewRecordOp CreateNewRecordOp(RowType type) 873 { 874 return new NewRecordOp(TypeUsage.Create(type)); 875 } 876 877 /// <summary> 878 /// A variant of the above method to create a NewRecordOp. An additional 879 /// argument - fields - is supplied, and the semantics is that only these fields 880 /// have any values specified as part of the Node. All other fields are 881 /// considered to be null. 882 /// </summary> 883 /// <param name="type"></param> 884 /// <param name="fields"></param> 885 /// <returns></returns> CreateNewRecordOp(TypeUsage type, List<EdmProperty> fields)886 internal NewRecordOp CreateNewRecordOp(TypeUsage type, 887 List<EdmProperty> fields) 888 { 889 return new NewRecordOp(type, fields); 890 } 891 892 /// <summary> 893 /// Creates a new VarRefOp 894 /// </summary> 895 /// <param name="v">The variable to reference</param> 896 /// <returns>A new VarRefOp that references the specified variable</returns> CreateVarRefOp(Var v)897 internal VarRefOp CreateVarRefOp(Var v) 898 { 899 return new VarRefOp(v); 900 } 901 /// <summary> 902 /// Creates a new ArithmeticOp of the specified type 903 /// </summary> 904 /// <param name="opType">An OpType that specifies one of the valid arithmetic operations: Plus, Minus, Multiply, Divide, Modulo, UnaryMinus</param> 905 /// <param name="type">Type metadata that specifies the result type of the arithmetic operation</param> 906 /// <returns>A new ArithmeticOp of the specified arithmetic OpType</returns> CreateArithmeticOp(OpType opType, TypeUsage type)907 internal ArithmeticOp CreateArithmeticOp(OpType opType, TypeUsage type) 908 { 909 return new ArithmeticOp(opType, type); 910 } 911 912 /// <summary> 913 /// Creates a new PropertyOp 914 /// </summary> 915 /// <param name="prop">EdmProperty metadata that specifies the property</param> 916 /// <returns>A new PropertyOp that references the specified property metadata</returns> CreatePropertyOp(EdmMember prop)917 internal PropertyOp CreatePropertyOp(EdmMember prop) 918 { 919 // 920 // Track all rel-properties 921 // 922 NavigationProperty navProp = prop as NavigationProperty; 923 if (navProp != null) 924 { 925 RelProperty relProperty = new RelProperty(navProp.RelationshipType, navProp.FromEndMember, navProp.ToEndMember); 926 AddRelPropertyReference(relProperty); 927 RelProperty inverseRelProperty = new RelProperty(navProp.RelationshipType, navProp.ToEndMember, navProp.FromEndMember); 928 AddRelPropertyReference(inverseRelProperty); 929 } 930 931 // Actually create the propertyOp 932 return new PropertyOp(Helper.GetModelTypeUsage(prop), prop); 933 } 934 935 /// <summary> 936 /// Create a "relationship" propertyOp 937 /// </summary> 938 /// <param name="prop">the relationship property</param> 939 /// <returns>a RelPropertyOp</returns> CreateRelPropertyOp(RelProperty prop)940 internal RelPropertyOp CreateRelPropertyOp(RelProperty prop) 941 { 942 AddRelPropertyReference(prop); 943 return new RelPropertyOp(prop.ToEnd.TypeUsage, prop); 944 } 945 946 /// <summary> 947 /// Creates a new RefOp 948 /// </summary> 949 /// <param name="entitySet">The EntitySet to which the ref refers</param> 950 /// <param name="type">The result type of the RefOp</param> 951 /// <returns>A new RefOp that references the specified EntitySet and has the specified result type</returns> CreateRefOp(EntitySet entitySet, TypeUsage type)952 internal RefOp CreateRefOp(EntitySet entitySet, TypeUsage type) 953 { 954 return new RefOp(entitySet, type); 955 } 956 957 /// <summary> 958 /// Creates a new ExistsOp 959 /// </summary> 960 /// <returns>A new ExistsOp</returns> CreateExistsOp()961 internal ExistsOp CreateExistsOp() 962 { 963 return new ExistsOp(this.BooleanType); 964 } 965 /// <summary> 966 /// Creates a new ElementOp 967 /// </summary> 968 /// <param name="type">Type metadata that specifies the result (element) type</param> 969 /// <returns>A new ElementOp with the specified result type</returns> CreateElementOp(TypeUsage type)970 internal ElementOp CreateElementOp(TypeUsage type) 971 { 972 return new ElementOp(type); 973 } 974 975 /// <summary> 976 /// Creates a new GetEntityRefOp: a ref-extractor (from an entity instance) Op 977 /// </summary> 978 /// <param name="type">Type metadata that specifies the result type</param> 979 /// <returns>A new GetEntityKeyOp with the specified result type</returns> CreateGetEntityRefOp(TypeUsage type)980 internal GetEntityRefOp CreateGetEntityRefOp(TypeUsage type) 981 { 982 return new GetEntityRefOp(type); 983 } 984 /// <summary> 985 /// Creates a new GetRefKeyOp: a key-extractor (from a ref instance) Op 986 /// </summary> 987 /// <param name="type">Type metadata that specifies the result type</param> 988 /// <returns>A new GetRefKeyOp with the specified result type</returns> CreateGetRefKeyOp(TypeUsage type)989 internal GetRefKeyOp CreateGetRefKeyOp(TypeUsage type) 990 { 991 return new GetRefKeyOp(type); 992 } 993 994 /// <summary> 995 /// Creates a new CollectOp 996 /// </summary> 997 /// <param name="type">Type metadata that specifies the result type of the Nest operation</param> 998 /// <returns>A new NestOp with the specified result type</returns> CreateCollectOp(TypeUsage type)999 internal CollectOp CreateCollectOp(TypeUsage type) 1000 { 1001 return new CollectOp(type); 1002 } 1003 1004 /// <summary> 1005 /// Create a DerefOp 1006 /// </summary> 1007 /// <param name="type">Entity type of the target entity</param> 1008 /// <returns>a DerefOp</returns> CreateDerefOp(TypeUsage type)1009 internal DerefOp CreateDerefOp(TypeUsage type) 1010 { 1011 return new DerefOp(type); 1012 } 1013 1014 /// <summary> 1015 /// Create a new NavigateOp node 1016 /// </summary> 1017 /// <param name="type">the output type of the navigateOp</param> 1018 /// <param name="relProperty">the relationship property</param> 1019 /// <returns>the navigateOp</returns> CreateNavigateOp(TypeUsage type, RelProperty relProperty)1020 internal NavigateOp CreateNavigateOp(TypeUsage type, RelProperty relProperty) 1021 { 1022 // keep track of rel-properties 1023 AddRelPropertyReference(relProperty); 1024 return new NavigateOp(type, relProperty); 1025 } 1026 1027 #endregion 1028 1029 #region AncillaryOps 1030 1031 /// <summary> 1032 /// Creates a VarDefListOp 1033 /// </summary> 1034 /// <returns>A new VarDefListOp</returns> CreateVarDefListOp()1035 internal VarDefListOp CreateVarDefListOp() 1036 { 1037 return VarDefListOp.Instance; 1038 } 1039 /// <summary> 1040 /// Creates a VarDefOp (for a computed var) 1041 /// </summary> 1042 /// <param name="v">The computed var</param> 1043 /// <returns>A new VarDefOp that references the computed var</returns> CreateVarDefOp(Var v)1044 internal VarDefOp CreateVarDefOp(Var v) 1045 { 1046 return new VarDefOp(v); 1047 } 1048 1049 /// <summary> 1050 /// Create a VarDefOp and the associated node for an expression. 1051 /// We create a computedVar first - of the same type as the expression, and 1052 /// then create a VarDefOp for the computed Var. Finally, we create a Node for 1053 /// the VarDefOp 1054 /// </summary> 1055 /// <param name="definingExpr"></param> 1056 /// <param name="computedVar">new Var produced</param> 1057 /// <returns></returns> CreateVarDefNode(Node definingExpr, out Var computedVar)1058 internal Node CreateVarDefNode(Node definingExpr, out Var computedVar) 1059 { 1060 Debug.Assert(definingExpr.Op != null); 1061 ScalarOp scalarOp = definingExpr.Op as ScalarOp; 1062 Debug.Assert(scalarOp != null); 1063 computedVar = this.CreateComputedVar(scalarOp.Type); 1064 VarDefOp varDefOp = this.CreateVarDefOp(computedVar); 1065 Node varDefNode = this.CreateNode(varDefOp, definingExpr); 1066 return varDefNode; 1067 } 1068 1069 /// <summary> 1070 /// Creates a VarDefListOp with a single child - a VarDefOp created as in the function 1071 /// above. 1072 /// </summary> 1073 /// <param name="definingExpr"></param> 1074 /// <param name="computedVar">the computed Var produced</param> 1075 /// <returns></returns> CreateVarDefListNode(Node definingExpr, out Var computedVar)1076 internal Node CreateVarDefListNode(Node definingExpr, out Var computedVar) 1077 { 1078 Node varDefNode = this.CreateVarDefNode(definingExpr, out computedVar); 1079 VarDefListOp op = this.CreateVarDefListOp(); 1080 Node varDefListNode = this.CreateNode(op, varDefNode); 1081 return varDefListNode; 1082 } 1083 #endregion 1084 1085 #region RelOps 1086 1087 /// <summary> 1088 /// Creates a new ScanTableOp 1089 /// </summary> 1090 /// <param name="tableMetadata">A Table metadata instance that specifies the table that should be scanned</param> 1091 /// <returns>A new ScanTableOp that references a new Table instance based on the specified table metadata</returns> CreateScanTableOp(TableMD tableMetadata)1092 internal ScanTableOp CreateScanTableOp(TableMD tableMetadata) 1093 { 1094 Table table = this.CreateTableInstance(tableMetadata); 1095 return CreateScanTableOp(table); 1096 } 1097 /// <summary> 1098 /// A variant of the above 1099 /// </summary> 1100 /// <param name="table">The table instance</param> 1101 /// <returns>a new ScanTableOp</returns> CreateScanTableOp(Table table)1102 internal ScanTableOp CreateScanTableOp(Table table) 1103 { 1104 return new ScanTableOp(table); 1105 } 1106 1107 /// <summary> 1108 /// Creates an instance of a ScanViewOp 1109 /// </summary> 1110 /// <param name="table">the table instance</param> 1111 /// <returns>a new ScanViewOp</returns> CreateScanViewOp(Table table)1112 internal ScanViewOp CreateScanViewOp(Table table) 1113 { 1114 return new ScanViewOp(table); 1115 } 1116 /// <summary> 1117 /// Creates an instance of a ScanViewOp 1118 /// </summary> 1119 /// <param name="tableMetadata">the table metadata</param> 1120 /// <returns>a new ScanViewOp</returns> CreateScanViewOp(TableMD tableMetadata)1121 internal ScanViewOp CreateScanViewOp(TableMD tableMetadata) 1122 { 1123 Table table = this.CreateTableInstance(tableMetadata); 1124 return this.CreateScanViewOp(table); 1125 } 1126 /// <summary> 1127 /// Creates a new UnnestOp, which creates a streaming result from a scalar (non-RelOp) value 1128 /// </summary> 1129 /// <param name="v">The Var that indicates the value to unnest</param> 1130 /// <returns>A new UnnestOp that targets the specified Var</returns> CreateUnnestOp(Var v)1131 internal UnnestOp CreateUnnestOp(Var v) 1132 { 1133 Table t = this.CreateTableInstance(Command.CreateTableDefinition(TypeHelpers.GetEdmType<CollectionType>(v.Type).TypeUsage)); 1134 return CreateUnnestOp(v, t); 1135 } 1136 1137 /// <summary> 1138 /// Creates a new UnnestOp - a variant of the above with the Table supplied 1139 /// </summary> 1140 /// <param name="v">the unnest Var</param> 1141 /// <param name="t">the table instance</param> 1142 /// <returns>a new UnnestOp</returns> CreateUnnestOp(Var v, Table t)1143 internal UnnestOp CreateUnnestOp(Var v, Table t) 1144 { 1145 return new UnnestOp(v, t); 1146 } 1147 1148 /// <summary> 1149 /// Creates a new FilterOp 1150 /// </summary> 1151 /// <returns>A new FilterOp</returns> CreateFilterOp()1152 internal FilterOp CreateFilterOp() 1153 { 1154 return FilterOp.Instance; 1155 } 1156 1157 /// <summary> 1158 /// Creates a new ProjectOp 1159 /// </summary> 1160 /// <param name="vars">A VarSet that specifies the Vars produced by the projection</param> 1161 /// <returns>A new ProjectOp with the specified output VarSet</returns> CreateProjectOp(VarVec vars)1162 internal ProjectOp CreateProjectOp(VarVec vars) 1163 { 1164 return new ProjectOp(vars); 1165 } 1166 /// <summary> 1167 /// A variant of the above where the ProjectOp produces exactly one var 1168 /// </summary> 1169 /// <param name="v"></param> 1170 /// <returns></returns> CreateProjectOp(Var v)1171 internal ProjectOp CreateProjectOp(Var v) 1172 { 1173 VarVec varSet = this.CreateVarVec(); 1174 varSet.Set(v); 1175 return new ProjectOp(varSet); 1176 } 1177 1178 #region JoinOps 1179 1180 /// <summary> 1181 /// Creates a new InnerJoinOp 1182 /// </summary> 1183 /// <returns>A new InnerJoinOp</returns> CreateInnerJoinOp()1184 internal InnerJoinOp CreateInnerJoinOp() 1185 { 1186 return InnerJoinOp.Instance; 1187 } 1188 1189 /// <summary> 1190 /// Creates a new LeftOuterJoinOp 1191 /// </summary> 1192 /// <returns>A new LeftOuterJoinOp</returns> CreateLeftOuterJoinOp()1193 internal LeftOuterJoinOp CreateLeftOuterJoinOp() 1194 { 1195 return LeftOuterJoinOp.Instance; 1196 } 1197 1198 /// <summary> 1199 /// Creates a new FullOuterJoinOp 1200 /// </summary> 1201 /// <returns>A new FullOuterJoinOp</returns> CreateFullOuterJoinOp()1202 internal FullOuterJoinOp CreateFullOuterJoinOp() 1203 { 1204 return FullOuterJoinOp.Instance; 1205 } 1206 1207 /// <summary> 1208 /// Creates a new CrossJoinOp 1209 /// </summary> 1210 /// <returns>A new CrossJoinOp</returns> CreateCrossJoinOp()1211 internal CrossJoinOp CreateCrossJoinOp() 1212 { 1213 return CrossJoinOp.Instance; 1214 } 1215 1216 #endregion 1217 1218 #region ApplyOps 1219 1220 /// <summary> 1221 /// Creates a new CrossApplyOp 1222 /// </summary> 1223 /// <returns>A new CrossApplyOp</returns> CreateCrossApplyOp()1224 internal CrossApplyOp CreateCrossApplyOp() 1225 { 1226 return CrossApplyOp.Instance; 1227 } 1228 /// <summary> 1229 /// Creates a new OuterApplyOp 1230 /// </summary> 1231 /// <returns>A new OuterApplyOp</returns> CreateOuterApplyOp()1232 internal OuterApplyOp CreateOuterApplyOp() 1233 { 1234 return OuterApplyOp.Instance; 1235 } 1236 1237 #endregion 1238 1239 #region SortKeys 1240 1241 /// <summary> 1242 /// Creates a new SortKey with the specified var, order and collation 1243 /// </summary> 1244 /// <param name="v">The variable to sort on</param> 1245 /// <param name="asc">The sort order (true for ascending, false for descending)</param> 1246 /// <param name="collation">The sort collation</param> 1247 /// <returns>A new SortKey with the specified var, order and collation</returns> CreateSortKey(Var v, bool asc, string collation)1248 internal static SortKey CreateSortKey(Var v, bool asc, string collation) 1249 { 1250 return new SortKey(v, asc, collation); 1251 } 1252 /// <summary> 1253 /// Creates a new SortKey with the specified var and order 1254 /// </summary> 1255 /// <param name="v">The variable to sort on</param> 1256 /// <param name="asc">The sort order (true for ascending, false for descending)</param> 1257 /// <returns>A new SortKey with the specified var and order</returns> CreateSortKey(Var v, bool asc)1258 internal static SortKey CreateSortKey(Var v, bool asc) 1259 { 1260 return new SortKey(v, asc, ""); 1261 } 1262 1263 /// <summary> 1264 /// Creates a new SortKey with the specified var 1265 /// </summary> 1266 /// <param name="v">The variable to sort on</param> 1267 /// <returns>A new SortKey with the specified var</returns> CreateSortKey(Var v)1268 internal static SortKey CreateSortKey(Var v) 1269 { 1270 return new SortKey(v, true, ""); 1271 } 1272 1273 #endregion 1274 1275 /// <summary> 1276 /// Creates a new SortOp 1277 /// </summary> 1278 /// <param name="sortKeys">The list of SortKeys that define the sort var, order and collation for each sort key</param> 1279 /// <returns>A new SortOp with the specified sort keys</returns> CreateSortOp(List<SortKey> sortKeys)1280 internal SortOp CreateSortOp(List<SortKey> sortKeys) 1281 { 1282 return new SortOp(sortKeys); 1283 } 1284 1285 /// <summary> 1286 /// Creates a new ConstrainedSortOp 1287 /// </summary> 1288 /// <param name="sortKeys">The list of SortKeys that define the sort var, order and collation for each sort key</param> 1289 /// <returns>A new ConstrainedSortOp with the specified sort keys and a default WithTies value of false</returns> CreateConstrainedSortOp(List<SortKey> sortKeys)1290 internal ConstrainedSortOp CreateConstrainedSortOp(List<SortKey> sortKeys) 1291 { 1292 return new ConstrainedSortOp(sortKeys, false); 1293 } 1294 1295 /// <summary> 1296 /// Creates a new ConstrainedSortOp 1297 /// </summary> 1298 /// <param name="sortKeys">The list of SortKeys that define the sort var, order and collation for each sort key</param> 1299 /// <param name="withTies">The value to use for the WithTies property of the new ConstrainedSortOp</param> 1300 /// <returns>A new ConstrainedSortOp with the specified sort keys and WithTies value</returns> CreateConstrainedSortOp(List<SortKey> sortKeys, bool withTies)1301 internal ConstrainedSortOp CreateConstrainedSortOp(List<SortKey> sortKeys, bool withTies) 1302 { 1303 return new ConstrainedSortOp(sortKeys, withTies); 1304 } 1305 1306 /// <summary> 1307 /// Creates a new GroupByOp 1308 /// </summary> 1309 /// <param name="gbyKeys">A VarSet that specifies the Key variables produced by the GroupByOp</param> 1310 /// <param name="outputs">A VarSet that specifies all (Key and Aggregate) variables produced by the GroupByOp</param> 1311 /// <returns>A new GroupByOp with the specified key and output VarSets</returns> CreateGroupByOp(VarVec gbyKeys, VarVec outputs)1312 internal GroupByOp CreateGroupByOp(VarVec gbyKeys, VarVec outputs) 1313 { 1314 return new GroupByOp(gbyKeys, outputs); 1315 } 1316 1317 /// <summary> 1318 /// Creates a new GroupByIntoOp 1319 /// </summary> 1320 /// <param name="gbyKeys">A VarSet that specifies the Key variables produced by the GroupByOp</param> 1321 /// <param name="outputs">A VarSet that specifies the vars from the input that represent the real grouping input</param> 1322 /// <param name="inputs">A VarSet that specifies all (Key and Aggregate) variables produced by the GroupByOp</param> 1323 /// <returns>A new GroupByOp with the specified key and output VarSets</returns> CreateGroupByIntoOp(VarVec gbyKeys, VarVec inputs, VarVec outputs)1324 internal GroupByIntoOp CreateGroupByIntoOp(VarVec gbyKeys, VarVec inputs, VarVec outputs) 1325 { 1326 return new GroupByIntoOp(gbyKeys, inputs, outputs); 1327 } 1328 1329 /// <summary> 1330 /// Creates a new DistinctOp 1331 /// <param name="keyVars">list of key vars</param> 1332 /// </summary> 1333 /// <returns>A new DistinctOp</returns> CreateDistinctOp(VarVec keyVars)1334 internal DistinctOp CreateDistinctOp(VarVec keyVars) 1335 { 1336 return new DistinctOp(keyVars); 1337 } 1338 /// <summary> 1339 /// An overload of the above - where the distinct has exactly one key 1340 /// </summary> 1341 /// <param name="keyVar"></param> 1342 /// <returns></returns> CreateDistinctOp(Var keyVar)1343 internal DistinctOp CreateDistinctOp(Var keyVar) 1344 { 1345 return new DistinctOp(this.CreateVarVec(keyVar)); 1346 } 1347 1348 /// <summary> 1349 /// Creates a new UnionAllOp 1350 /// </summary> 1351 /// <param name="leftMap">Mappings from the Output Vars to the Vars produced by the left argument</param> 1352 /// <param name="rightMap">Mappings from the Output Vars to the Vars produced by the right argument</param> 1353 /// <returns>A UnionAllOp that references the specified left and right Vars</returns> CreateUnionAllOp(VarMap leftMap, VarMap rightMap)1354 internal UnionAllOp CreateUnionAllOp(VarMap leftMap, VarMap rightMap) 1355 { 1356 return CreateUnionAllOp(leftMap, rightMap, null); 1357 } 1358 1359 /// <summary> 1360 /// Creates a new UnionAllOp, with a branch descriminator. 1361 /// </summary> 1362 /// <param name="leftMap">Mappings from the Output Vars to the Vars produced by the left argument</param> 1363 /// <param name="rightMap">Mappings from the Output Vars to the Vars produced by the right argument</param> 1364 /// <param name="branchDiscriminator">Var that contains the branch discrimination value (may be null until key pullup occurs)</param> 1365 /// <returns>A UnionAllOp that references the specified left and right Vars</returns> CreateUnionAllOp(VarMap leftMap, VarMap rightMap, Var branchDiscriminator)1366 internal UnionAllOp CreateUnionAllOp(VarMap leftMap, VarMap rightMap, Var branchDiscriminator) 1367 { 1368 Debug.Assert(leftMap.Count == rightMap.Count, "VarMap count mismatch"); 1369 VarVec vec = this.CreateVarVec(); 1370 foreach (Var v in leftMap.Keys) 1371 { 1372 vec.Set(v); 1373 } 1374 return new UnionAllOp(vec, leftMap, rightMap, branchDiscriminator); 1375 } 1376 1377 /// <summary> 1378 /// Creates a new IntersectOp 1379 /// </summary> 1380 /// <param name="leftMap">Mappings from the Output Vars to the Vars produced by the left argument</param> 1381 /// <param name="rightMap">Mappings from the Output Vars to the Vars produced by the right argument</param> 1382 /// <returns>An IntersectOp that references the specified left and right Vars</returns> CreateIntersectOp(VarMap leftMap, VarMap rightMap)1383 internal IntersectOp CreateIntersectOp(VarMap leftMap, VarMap rightMap) 1384 { 1385 Debug.Assert(leftMap.Count == rightMap.Count, "VarMap count mismatch"); 1386 VarVec vec = this.CreateVarVec(); 1387 foreach (Var v in leftMap.Keys) 1388 { 1389 vec.Set(v); 1390 } 1391 return new IntersectOp(vec, leftMap, rightMap); 1392 } 1393 /// <summary> 1394 /// Creates a new ExceptOp 1395 /// </summary> 1396 /// <param name="leftMap">Mappings from the Output Vars to the Vars produced by the left argument</param> 1397 /// <param name="rightMap">Mappings from the Output Vars to the Vars produced by the right argument</param> 1398 /// <returns>An ExceptOp that references the specified left and right Vars</returns> CreateExceptOp(VarMap leftMap, VarMap rightMap)1399 internal ExceptOp CreateExceptOp(VarMap leftMap, VarMap rightMap) 1400 { 1401 Debug.Assert(leftMap.Count == rightMap.Count, "VarMap count mismatch"); 1402 VarVec vec = this.CreateVarVec(); 1403 foreach (Var v in leftMap.Keys) 1404 { 1405 vec.Set(v); 1406 } 1407 return new ExceptOp(vec, leftMap, rightMap); 1408 } 1409 1410 /// <summary> 1411 /// Create a single-row-op (the relop analog of Element) 1412 /// </summary> 1413 /// <returns></returns> CreateSingleRowOp()1414 internal SingleRowOp CreateSingleRowOp() 1415 { 1416 return SingleRowOp.Instance; 1417 } 1418 1419 /// <summary> 1420 /// Create a SingleRowTableOp - a table with exactly one row (and no columns) 1421 /// </summary> 1422 /// <returns></returns> CreateSingleRowTableOp()1423 internal SingleRowTableOp CreateSingleRowTableOp() 1424 { 1425 return SingleRowTableOp.Instance; 1426 } 1427 1428 #endregion 1429 1430 #region PhysicalOps 1431 /// <summary> 1432 /// Create a PhysicalProjectOp - with a columnMap describing the output 1433 /// </summary> 1434 /// <param name="outputVars">list of output vars</param> 1435 /// <param name="columnMap">columnmap describing the output element</param> 1436 /// <returns></returns> CreatePhysicalProjectOp(VarList outputVars, SimpleCollectionColumnMap columnMap)1437 internal PhysicalProjectOp CreatePhysicalProjectOp(VarList outputVars, SimpleCollectionColumnMap columnMap) 1438 { 1439 return new PhysicalProjectOp(outputVars, columnMap); 1440 } 1441 /// <summary> 1442 /// Create a physicalProjectOp - with a single column output 1443 /// </summary> 1444 /// <param name="outputVar">the output element</param> 1445 /// <returns></returns> CreatePhysicalProjectOp(Var outputVar)1446 internal PhysicalProjectOp CreatePhysicalProjectOp(Var outputVar) 1447 { 1448 VarList varList = Command.CreateVarList(); 1449 varList.Add(outputVar); 1450 VarRefColumnMap varRefColumnMap = new VarRefColumnMap(outputVar); 1451 1452 SimpleCollectionColumnMap collectionColumnMap = new SimpleCollectionColumnMap( 1453 TypeUtils.CreateCollectionType(varRefColumnMap.Type), // type 1454 null, // name 1455 varRefColumnMap, // element map 1456 new SimpleColumnMap[0], // keys 1457 new SimpleColumnMap[0]); // foreign keys 1458 return CreatePhysicalProjectOp(varList, collectionColumnMap); 1459 } 1460 1461 /// <summary> 1462 /// Another overload - with an additional discriminatorValue. 1463 /// Should this be a subtype instead? 1464 /// </summary> 1465 /// <param name="collectionVar">the collectionVar</param> 1466 /// <param name="columnMap">column map for the collection element</param> 1467 /// <param name="flattenedElementVars">elementVars with any nested collections pulled up</param> 1468 /// <param name="keys">keys specific to this collection</param> 1469 /// <param name="sortKeys">sort keys specific to this collecion</param> 1470 /// <param name="discriminatorValue">discriminator value for this collection (under the current nestOp)</param> 1471 /// <returns>a new CollectionInfo instance</returns> CreateCollectionInfo(Var collectionVar, ColumnMap columnMap, VarList flattenedElementVars, VarVec keys, List<InternalTrees.SortKey> sortKeys, object discriminatorValue)1472 internal static CollectionInfo CreateCollectionInfo(Var collectionVar, ColumnMap columnMap, VarList flattenedElementVars, VarVec keys, List<InternalTrees.SortKey> sortKeys, object discriminatorValue) 1473 { 1474 return new CollectionInfo(collectionVar, columnMap, flattenedElementVars, keys, sortKeys, discriminatorValue); 1475 } 1476 1477 /// <summary> 1478 /// Create a singleStreamNestOp 1479 /// </summary> 1480 /// <param name="keys">keys for the nest operation</param> 1481 /// <param name="prefixSortKeys">list of prefix sort keys</param> 1482 /// <param name="postfixSortKeys">list of postfix sort keys</param> 1483 /// <param name="outputVars">List of outputVars</param> 1484 /// <param name="collectionInfoList">CollectionInfo for each collection </param> 1485 /// <param name="discriminatorVar">Var describing the discriminator</param> 1486 /// <returns></returns> CreateSingleStreamNestOp(VarVec keys, List<SortKey> prefixSortKeys, List<SortKey> postfixSortKeys, VarVec outputVars, List<CollectionInfo> collectionInfoList, Var discriminatorVar)1487 internal SingleStreamNestOp CreateSingleStreamNestOp(VarVec keys, 1488 List<SortKey> prefixSortKeys, List<SortKey> postfixSortKeys, 1489 VarVec outputVars, 1490 List<CollectionInfo> collectionInfoList, Var discriminatorVar) 1491 { 1492 return new SingleStreamNestOp(keys, prefixSortKeys, postfixSortKeys, outputVars, collectionInfoList, discriminatorVar); 1493 } 1494 1495 /// <summary> 1496 /// Create a MultiStreamNestOp 1497 /// </summary> 1498 /// <param name="prefixSortKeys">list of prefix sort keys</param> 1499 /// <param name="outputVars">List of outputVars</param> 1500 /// <param name="collectionInfoList">CollectionInfo for each collection element</param> 1501 /// <returns></returns> CreateMultiStreamNestOp(List<SortKey> prefixSortKeys, VarVec outputVars, List<CollectionInfo> collectionInfoList)1502 internal MultiStreamNestOp CreateMultiStreamNestOp(List<SortKey> prefixSortKeys, VarVec outputVars, 1503 List<CollectionInfo> collectionInfoList) 1504 { 1505 return new MultiStreamNestOp(prefixSortKeys, outputVars, collectionInfoList); 1506 } 1507 #endregion 1508 1509 #region NodeInfo 1510 /// <summary> 1511 /// Get auxilliary information for a Node 1512 /// </summary> 1513 /// <param name="n">the node</param> 1514 /// <returns>node info for this node</returns> GetNodeInfo(Node n)1515 internal NodeInfo GetNodeInfo(Node n) 1516 { 1517 return n.GetNodeInfo(this); 1518 } 1519 1520 /// <summary> 1521 /// Get extended node information for a RelOpNode 1522 /// </summary> 1523 /// <param name="n">the node</param> 1524 /// <returns>extended node info for this node</returns> GetExtendedNodeInfo(Node n)1525 internal ExtendedNodeInfo GetExtendedNodeInfo(Node n) 1526 { 1527 return n.GetExtendedNodeInfo(this); 1528 } 1529 /// <summary> 1530 /// Recompute the nodeinfo for a node, but only if has already been computed 1531 /// </summary> 1532 /// <param name="n">Node in question</param> RecomputeNodeInfo(Node n)1533 internal void RecomputeNodeInfo(Node n) 1534 { 1535 m_nodeInfoVisitor.RecomputeNodeInfo(n); 1536 } 1537 #endregion 1538 1539 #region KeyInfo 1540 /// <summary> 1541 /// Pulls up keys if necessary and gets the key information for a Node 1542 /// </summary> 1543 /// <param name="n">node</param> 1544 /// <returns>key information</returns> PullupKeys(Node n)1545 internal KeyVec PullupKeys(Node n) 1546 { 1547 return m_keyPullupVisitor.GetKeys(n); 1548 } 1549 #endregion 1550 1551 #region Type Comparisons 1552 // 1553 // The functions described in this region are used through out the 1554 // PlanCompiler to reason about type equality. Make sure that you 1555 // use these and these alone 1556 // 1557 1558 /// <summary> 1559 /// Check to see if two types are considered "equal" for the purposes 1560 /// of the plan compiler. 1561 /// Two types are considered to be equal if their "identities" are equal. 1562 /// </summary> 1563 /// <param name="x"></param> 1564 /// <param name="y"></param> 1565 /// <returns>true, if the types are "equal"</returns> EqualTypes(TypeUsage x, TypeUsage y)1566 internal static bool EqualTypes(TypeUsage x, TypeUsage y) 1567 { 1568 return PlanCompiler.TypeUsageEqualityComparer.Instance.Equals(x, y); 1569 } 1570 /// <summary> 1571 /// Check to see if two types are considered "equal" for the purposes 1572 /// of the plan compiler 1573 /// </summary> 1574 /// <param name="x"></param> 1575 /// <param name="y"></param> 1576 /// <returns>true, if the types are "equal"</returns> EqualTypes(EdmType x, EdmType y)1577 internal static bool EqualTypes(EdmType x, EdmType y) 1578 { 1579 return PlanCompiler.TypeUsageEqualityComparer.Equals(x, y); 1580 } 1581 #endregion 1582 1583 #region Builder Methods 1584 /// <summary> 1585 /// Builds out a UNION-ALL ladder from a sequence of node,var pairs. 1586 /// Assumption: Each node produces exactly one Var 1587 /// 1588 /// If the input sequence has zero elements, we return null 1589 /// If the input sequence has one element, we return that single element 1590 /// Otherwise, we build out a UnionAll ladder from each of the inputs. If the input sequence was {A,B,C,D}, 1591 /// we build up a union-all ladder that looks like 1592 /// (((A UA B) UA C) UA D) 1593 /// </summary> 1594 /// <param name="inputNodes">list of input nodes - one for each branch</param> 1595 /// <param name="inputVars">list of input vars - N for each branch</param> 1596 /// <param name="resultNode">the resulting union-all subtree</param> 1597 /// <param name="resultVar">the output vars from the union-all subtree</param> BuildUnionAllLadder( IList<Node> inputNodes, IList<Var> inputVars, out Node resultNode, out IList<Var> resultVars)1598 internal void BuildUnionAllLadder( 1599 IList<Node> inputNodes, IList<Var> inputVars, 1600 out Node resultNode, out IList<Var> resultVars) 1601 { 1602 if (inputNodes.Count == 0) 1603 { 1604 resultNode = null; 1605 resultVars = null; 1606 return; 1607 } 1608 1609 int varPerNode = inputVars.Count / inputNodes.Count; 1610 Debug.Assert((inputVars.Count % inputNodes.Count == 0) && (varPerNode >= 1), "Inconsistent nodes/vars count:" + inputNodes.Count + "," + inputVars.Count); 1611 1612 if (inputNodes.Count == 1) 1613 { 1614 resultNode = inputNodes[0]; 1615 resultVars = inputVars; 1616 return; 1617 } 1618 1619 List<Var> unionAllVars = new List<Var>(); 1620 1621 Node unionAllNode = inputNodes[0]; 1622 for (int j = 0; j < varPerNode; j++) 1623 { 1624 unionAllVars.Add(inputVars[j]); 1625 } 1626 1627 for (int i = 1; i < inputNodes.Count; i++) 1628 { 1629 VarMap leftVarMap = this.CreateVarMap(); 1630 VarMap rightVarMap = this.CreateVarMap(); 1631 List<Var> setOpVars = new List<Var>(); 1632 for (int j = 0; j < varPerNode; j++) 1633 { 1634 SetOpVar newVar = this.CreateSetOpVar(unionAllVars[j].Type); 1635 setOpVars.Add(newVar); 1636 leftVarMap.Add(newVar, unionAllVars[j]); 1637 rightVarMap.Add(newVar, inputVars[i * varPerNode + j]); 1638 } 1639 Op unionAllOp = this.CreateUnionAllOp(leftVarMap, rightVarMap); 1640 unionAllNode = this.CreateNode(unionAllOp, unionAllNode, inputNodes[i]); 1641 unionAllVars = setOpVars; 1642 } 1643 1644 resultNode = unionAllNode; 1645 resultVars = unionAllVars; 1646 } 1647 1648 /// <summary> 1649 /// A simplified version of the method above - each branch can produce only one var 1650 /// </summary> 1651 /// <param name="inputNodes"></param> 1652 /// <param name="inputVars"></param> 1653 /// <param name="resultNode"></param> 1654 /// <param name="resultVar"></param> BuildUnionAllLadder(IList<Node> inputNodes, IList<Var> inputVars, out Node resultNode, out Var resultVar)1655 internal void BuildUnionAllLadder(IList<Node> inputNodes, IList<Var> inputVars, 1656 out Node resultNode, out Var resultVar) 1657 { 1658 Debug.Assert(inputNodes.Count == inputVars.Count, "Count mismatch:" + inputNodes.Count + "," + inputVars.Count); 1659 IList<Var> varList; 1660 BuildUnionAllLadder(inputNodes, inputVars, out resultNode, out varList); 1661 if (varList != null && varList.Count > 0) 1662 { 1663 resultVar = varList[0]; 1664 } 1665 else 1666 { 1667 resultVar = null; 1668 } 1669 } 1670 1671 /// <summary> 1672 /// Build a projectOp tree over the input. 1673 /// This function builds a projectOp tree over the input. The Outputs (vars) of the project are the 1674 /// list of vars from the input (inputVars), plus one computed Var for each of the computed expressions 1675 /// (computedExpressions) 1676 /// </summary> 1677 /// <param name="inputNode">the input relop to the project</param> 1678 /// <param name="inputVars">List of vars from the input that need to be projected</param> 1679 /// <param name="computedExpressions">list (possibly empty) of any computed expressions</param> 1680 /// <returns></returns> BuildProject(Node inputNode, IEnumerable<Var> inputVars, IEnumerable<Node> computedExpressions)1681 internal Node BuildProject(Node inputNode, IEnumerable<Var> inputVars, 1682 IEnumerable<Node> computedExpressions) 1683 { 1684 Debug.Assert(inputNode.Op.IsRelOp, "Expected a RelOp. Found " + inputNode.Op.OpType); 1685 1686 VarDefListOp varDefListOp = this.CreateVarDefListOp(); 1687 Node varDefListNode = this.CreateNode(varDefListOp); 1688 VarVec projectVars = this.CreateVarVec(inputVars); 1689 foreach (Node expr in computedExpressions) 1690 { 1691 Var v = this.CreateComputedVar(expr.Op.Type); 1692 projectVars.Set(v); 1693 VarDefOp varDefOp = this.CreateVarDefOp(v); 1694 Node varDefNode = this.CreateNode(varDefOp, expr); 1695 varDefListNode.Children.Add(varDefNode); 1696 } 1697 Node projectNode = this.CreateNode( 1698 this.CreateProjectOp(projectVars), 1699 inputNode, 1700 varDefListNode); 1701 return projectNode; 1702 } 1703 1704 /// <summary> 1705 /// A "simpler" builder method for ProjectOp. The assumption is that the only output is the 1706 /// (var corresponding to) the computedExpression. None of the Vars of the "input" are projected out 1707 /// 1708 /// The single output Var is returned in the "outputVar" parameter 1709 /// </summary> 1710 /// <param name="input">the input relop</param> 1711 /// <param name="computedExpression">the computed expression</param> 1712 /// <param name="projectVar">(output) the computed var corresponding to the computed expression</param> 1713 /// <returns>the new project subtree node</returns> BuildProject(Node input, Node computedExpression, out Var projectVar)1714 internal Node BuildProject(Node input, Node computedExpression, out Var projectVar) 1715 { 1716 Node projectNode = BuildProject(input, new Var[] { }, new Node[] { computedExpression }); 1717 projectVar = ((ProjectOp)projectNode.Op).Outputs.First; 1718 return projectNode; 1719 } 1720 1721 /// <summary> 1722 /// Build the equivalent of an OfTypeExpression over the input (ie) produce the set of values from the 1723 /// input that are of the desired type (exactly of the desired type, if the "includeSubtypes" parameter is false). 1724 /// 1725 /// Further more, "update" the result element type to be the desired type. 1726 /// 1727 /// We accomplish this by first building a FilterOp with an IsOf (or an IsOfOnly) predicate for the desired 1728 /// type. We then build out a ProjectOp over the FilterOp, where we introduce a "Fake" TreatOp over the input 1729 /// element to cast it to the right type. The "Fake" TreatOp is only there for "compile-time" typing reasons, 1730 /// and will be ignored in the rest of the plan compiler 1731 /// </summary> 1732 /// <param name="inputNode">the input collection</param> 1733 /// <param name="inputVar">the single Var produced by the input collection</param> 1734 /// <param name="desiredType">the desired element type </param> 1735 /// <param name="includeSubtypes">do we include subtypes of the desired element type</param> 1736 /// <param name="resultNode">the result subtree</param> 1737 /// <param name="resultVar">the single Var produced by the result subtree</param> BuildOfTypeTree(Node inputNode, Var inputVar, TypeUsage desiredType, bool includeSubtypes, out Node resultNode, out Var resultVar)1738 internal void BuildOfTypeTree(Node inputNode, Var inputVar, TypeUsage desiredType, bool includeSubtypes, 1739 out Node resultNode, out Var resultVar) 1740 { 1741 Op isOfOp = includeSubtypes ? this.CreateIsOfOp(desiredType) : this.CreateIsOfOnlyOp(desiredType); 1742 Node predicate = this.CreateNode(isOfOp, this.CreateNode(this.CreateVarRefOp(inputVar))); 1743 Node filterNode = this.CreateNode(this.CreateFilterOp(), inputNode, predicate); 1744 1745 resultNode = BuildFakeTreatProject(filterNode, inputVar, desiredType, out resultVar); 1746 } 1747 1748 /// Builds out a ProjectOp over the input that introduces a "Fake" TreatOp over the input Var to cast it to the desired type 1749 /// The "Fake" TreatOp is only there for "compile-time" typing reasons, and will be ignored in the rest of the plan compiler. 1750 /// </summary> 1751 /// <param name="inputNode">the input collection</param> 1752 /// <param name="inputVar">the single Var produced by the input collection</param> 1753 /// <param name="desiredType">the desired element type </param> 1754 /// <param name="resultVar">the single Var produced by the result subtree</param> 1755 /// <returns>the result subtree</returns> BuildFakeTreatProject(Node inputNode, Var inputVar, TypeUsage desiredType, out Var resultVar)1756 internal Node BuildFakeTreatProject(Node inputNode, Var inputVar, TypeUsage desiredType, out Var resultVar) 1757 { 1758 Node treatNode = this.CreateNode(this.CreateFakeTreatOp(desiredType), 1759 this.CreateNode(this.CreateVarRefOp(inputVar))); 1760 Node resultNode = this.BuildProject(inputNode, treatNode, out resultVar); 1761 return resultNode; 1762 } 1763 1764 /// <summary> 1765 /// Build a comparisonOp over the input arguments. Build SoftCasts over the inputs, if we need 1766 /// to. 1767 /// </summary> 1768 /// <param name="opType">the comparison optype</param> 1769 /// <param name="arg0">Arg 0</param> 1770 /// <param name="arg1">Arg 1</param> 1771 /// <returns>the resulting comparison tree</returns> BuildComparison(OpType opType, Node arg0, Node arg1)1772 internal Node BuildComparison(OpType opType, Node arg0, Node arg1) 1773 { 1774 if (!Command.EqualTypes(arg0.Op.Type, arg1.Op.Type)) 1775 { 1776 TypeUsage commonType = TypeHelpers.GetCommonTypeUsage(arg0.Op.Type, arg1.Op.Type); 1777 Debug.Assert(commonType != null, "No common type for " + arg0.Op.Type + " and " + arg1.Op.Type); 1778 if (!EqualTypes(commonType, arg0.Op.Type)) 1779 { 1780 arg0 = this.CreateNode(this.CreateSoftCastOp(commonType), arg0); 1781 } 1782 if (!EqualTypes(commonType, arg1.Op.Type)) 1783 { 1784 arg1 = this.CreateNode(this.CreateSoftCastOp(commonType), arg1); 1785 } 1786 } 1787 Node newNode = this.CreateNode(this.CreateComparisonOp(opType), arg0, arg1); 1788 return newNode; 1789 } 1790 1791 /// <summary> 1792 /// Build up a CollectOp over a relop tree 1793 /// </summary> 1794 /// <param name="relOpNode">the relop tree</param> 1795 /// <param name="relOpVar">the single output var from the relop tree</param> 1796 /// <returns></returns> BuildCollect(Node relOpNode, Var relOpVar)1797 internal Node BuildCollect(Node relOpNode, Var relOpVar) 1798 { 1799 Node physicalProjectNode = this.CreateNode(this.CreatePhysicalProjectOp(relOpVar), relOpNode); 1800 TypeUsage collectOpType = TypeHelpers.CreateCollectionTypeUsage(relOpVar.Type); 1801 Node collectNode = this.CreateNode(this.CreateCollectOp(collectOpType), physicalProjectNode); 1802 return collectNode; 1803 } 1804 #endregion 1805 1806 #region Rel Properties 1807 /// <summary> 1808 /// Mark this rel-property as "referenced" in the current query, if the target 1809 /// end has multiplicity of one (or zero_or_one) 1810 /// </summary> 1811 /// <param name="relProperty">the rel-property</param> AddRelPropertyReference(RelProperty relProperty)1812 private void AddRelPropertyReference(RelProperty relProperty) 1813 { 1814 if (relProperty.ToEnd.RelationshipMultiplicity != RelationshipMultiplicity.Many && 1815 !m_referencedRelProperties.Contains(relProperty)) 1816 { 1817 m_referencedRelProperties.Add(relProperty); 1818 } 1819 } 1820 1821 /// <summary> 1822 /// The set of referenced rel properties in the current query 1823 /// </summary> 1824 internal HashSet<RelProperty> ReferencedRelProperties 1825 { 1826 get { return m_referencedRelProperties; } 1827 } 1828 1829 /// <summary> 1830 /// Is this rel-property referenced in the query so far 1831 /// </summary> 1832 /// <param name="relProperty">the rel-property</param> 1833 /// <returns>true, if the rel property was referenced in the query</returns> IsRelPropertyReferenced(RelProperty relProperty)1834 internal bool IsRelPropertyReferenced(RelProperty relProperty) 1835 { 1836 bool ret = m_referencedRelProperties.Contains(relProperty); 1837 return ret; 1838 } 1839 #endregion 1840 1841 #endregion 1842 } 1843 1844 } 1845