public override WTableReference ToTableReference()
        {
            WSelectQueryBlock queryBlock = SubqueryContext.ToSelectQueryBlock();

            queryBlock.SelectElements.Clear();
            queryBlock.SelectElements.Add(SqlUtil.GetSelectScalarExpr(SqlUtil.GetFunctionCall(GremlinKeyword.func.Mean, SubqueryContext.PivotVariable.GetDefaultProjection().ToScalarExpression()), GremlinKeyword.TableDefaultColumnName));
            return(SqlUtil.GetDerivedTable(queryBlock, GetVariableName()));
        }
Example #2
0
 internal static WQueryDerivedTable GetDerivedTable(WSelectQueryBlock selectQueryBlock, string alias)
 {
     return(new WQueryDerivedTable()
     {
         QueryExpr = selectQueryBlock,
         Alias = GetIdentifier(alias)
     });
 }
Example #3
0
        public override WTableReference ToTableReference()
        {
            WSelectQueryBlock firstQueryExpr = new WSelectQueryBlock();

            foreach (var projectProperty in ProjectedProperties)
            {
                if (projectProperty == GremlinKeyword.TableDefaultColumnName)
                {
                    firstQueryExpr.SelectElements.Add(SqlUtil.GetSelectScalarExpr(InputVariable.GetDefaultProjection().ToScalarExpression(),
                                                                                  GremlinKeyword.TableDefaultColumnName));
                }
                else if (InputVariable.ProjectedProperties.Contains(projectProperty))
                {
                    firstQueryExpr.SelectElements.Add(
                        SqlUtil.GetSelectScalarExpr(
                            InputVariable.GetVariableProperty(projectProperty).ToScalarExpression(), projectProperty));
                }
                else
                {
                    firstQueryExpr.SelectElements.Add(
                        SqlUtil.GetSelectScalarExpr(SqlUtil.GetValueExpr(null), projectProperty));
                }
            }

            WSelectQueryBlock secondQueryExpr   = OptionalContext.ToSelectQueryBlock();
            bool HasAggregateFunctionAsChildren = false;

            foreach (var variable in OptionalContext.TableReferences)
            {
                if (variable is GremlinFoldVariable ||
                    variable is GremlinCountVariable ||
                    variable is GremlinMinVariable ||
                    variable is GremlinMaxVariable ||
                    variable is GremlinSumVariable ||
                    variable is GremlinMeanVariable ||
                    variable is GremlinTreeVariable)
                {
                    HasAggregateFunctionAsChildren = true;
                }
                var group = variable as GremlinGroupVariable;
                if (group != null && group.SideEffectKey == null)
                {
                    HasAggregateFunctionAsChildren = true;
                }
            }

            var WBinaryQueryExpression = SqlUtil.GetBinaryQueryExpr(firstQueryExpr, secondQueryExpr);

            List <WScalarExpression> parameters = new List <WScalarExpression>();

            parameters.Add(SqlUtil.GetScalarSubquery(WBinaryQueryExpression));
            var tableRef = SqlUtil.GetFunctionTableReference(GremlinKeyword.func.Optional, parameters, GetVariableName());

            ((WOptionalTableReference)tableRef).HasAggregateFunctionAsChildren = HasAggregateFunctionAsChildren;

            return(SqlUtil.GetCrossApplyTableReference(tableRef));
        }
Example #4
0
        internal static WSelectQueryBlock GetSimpleSelectQueryBlock(params GremlinVariableProperty[] projectProperties)
        {
            var queryBlock = new WSelectQueryBlock();

            foreach (var property in projectProperties)
            {
                queryBlock.SelectElements.Add(GetSelectScalarExpr(property.DefaultVariableProperty().ToScalarExpression()));
            }
            return(queryBlock);
        }
 /// <summary>
 /// Returns true if there are columns of a specific table referenced in a statement
 /// </summary>
 /// <param name="node">The query statement</param>
 /// <param name="tableName">the table for query</param>
 /// <param name="context">Sql context with table alias mapping</param>
 /// <param name="columnsOfNodeTables"></param>
 /// <param name="conn">A open Sql connection</param>
 /// <returns></returns>
 public bool Invoke(WSelectQueryBlock node, string tableName, WSqlTableContext context,
                    Dictionary <Tuple <string, string>, Dictionary <string, NodeColumns> > columnsOfNodeTables)
 {
     _tableExists        = false;
     _tableName          = tableName;
     _tableRef           = context[tableName] as WNamedTableReference;
     _columnTableMapping = context.GetColumnTableMapping(columnsOfNodeTables);
     node.Accept(this);
     return(_tableExists);
 }
 /// <summary>
 /// Returns true if there are columns of a specific table referenced in a statement
 /// </summary>
 /// <param name="node">The query statement</param>
 /// <param name="tableName">the table for query</param>
 /// <param name="context">Sql context with table alias mapping</param>
 /// <param name="columnsOfNodeTables"></param>
 /// <param name="conn">A open Sql connection</param>
 /// <returns></returns>
 public bool Invoke(WSelectQueryBlock node, string tableName, WSqlTableContext context,
     Dictionary<Tuple<string, string>, Dictionary<string, NodeColumns>> columnsOfNodeTables)
 {
     _tableExists = false;
     _tableName = tableName;
     _tableRef = context[tableName] as WNamedTableReference;
     _columnTableMapping = context.GetColumnToAliasMapping(columnsOfNodeTables);
     node.Accept(this);
     return _tableExists;
 }
Example #7
0
 internal static WQueryDerivedTable GetDerivedTable(WSelectQueryBlock selectQueryBlock, string alias)
 {
     return(new WQueryDerivedTable()
     {
         QueryExpr = selectQueryBlock,
         Alias = GetIdentifier(alias),
         Low = Int32.MinValue,
         High = Int32.MaxValue
     });
 }
 public override void Visit(WSelectQueryBlock node)
 {
     if (node.SelectElements.Any(e => e is WSelectStarExpression))
     {
         _tableExists = true;
     }
     else
     {
         base.Visit(node);
     }
 }
        public override WTableReference ToTableReference()
        {
            List <WScalarExpression> parameters       = new List <WScalarExpression>();
            WSelectQueryBlock        selectQueryBlock = ProjectContext.ToSelectQueryBlock(true);

            parameters.Add(SqlUtil.GetScalarSubquery(selectQueryBlock));
            parameters.Add(SqlUtil.GetValueExpr(SideEffectKey));
            var tableRef = SqlUtil.GetFunctionTableReference(GremlinKeyword.func.Store, parameters, GetVariableName());

            return(SqlUtil.GetCrossApplyTableReference(tableRef));
        }
Example #10
0
        public int Invoke(
            WSelectQueryBlock selectQueryBlock)
        {
            aggregateFunctionCount = 0;

            if (selectQueryBlock != null)
            {
                selectQueryBlock.Accept(this);
            }

            return(aggregateFunctionCount);
        }
        public override WTableReference ToTableReference()
        {
            WSelectQueryBlock queryBlock = SubqueryContext.ToSelectQueryBlock();

            queryBlock.SelectElements.Clear();
            List <WScalarExpression> foldParameters = new List <WScalarExpression> {
                SubqueryContext.PivotVariable.ToCompose1()
            };

            queryBlock.SelectElements.Add(SqlUtil.GetSelectScalarExpr(SqlUtil.GetFunctionCall(GremlinKeyword.func.Fold, foldParameters), GremlinKeyword.TableDefaultColumnName));
            return(SqlUtil.GetDerivedTable(queryBlock, GetVariableName()));
        }
Example #12
0
 private WSelectQueryBlock GetSelectQueryBlock(GremlinToSqlContext context)
 {
     if (context == null)
     {
         var queryBlock = new WSelectQueryBlock();
         queryBlock.SelectElements.Add(SqlUtil.GetSelectScalarExpr(InputVariable.GetDefaultProjection().ToScalarExpression()));
         return(queryBlock);
     }
     else
     {
         return(context.ToSelectQueryBlock());
     }
 }
        public override WTableReference ToTableReference()
        {
            List <WScalarExpression> parameters = new List <WScalarExpression>();

            for (var i = 0; i < ProjectKeys.Count; i++)
            {
                WSelectQueryBlock selectBlock = ProjectContextList[i % ProjectContextList.Count].ToSelectQueryBlock(true);
                parameters.Add(SqlUtil.GetScalarSubquery(selectBlock));
                parameters.Add(SqlUtil.GetValueExpr(ProjectKeys[i]));
            }
            var tableRef = SqlUtil.GetFunctionTableReference(GremlinKeyword.func.Project, parameters, GetVariableName());

            return(SqlUtil.GetCrossApplyTableReference(tableRef));
        }
Example #14
0
        public override WTableReference ToTableReference()
        {
            List <WScalarExpression> parameters = new List <WScalarExpression>();
            //TODO: refactor
            WSelectQueryBlock selectQueryBlock = ProjectContext.ToSelectQueryBlock();

            selectQueryBlock.SelectElements.Clear();
            selectQueryBlock.SelectElements.Add(SqlUtil.GetSelectScalarExpr(ProjectContext.PivotVariable.ToCompose1(), GremlinKeyword.TableDefaultColumnName));
            parameters.Add(SqlUtil.GetScalarSubquery(selectQueryBlock));
            parameters.Add(SqlUtil.GetValueExpr(SideEffectKey));
            var secondTableRef = SqlUtil.GetFunctionTableReference(GremlinKeyword.func.Store, parameters, this, GetVariableName());

            return(SqlUtil.GetCrossApplyTableReference(null, secondTableRef));
        }
Example #15
0
 public WDeleteEdgeSpecification(WSelectQueryBlock deleteSpec)
 {
     SelectDeleteExpr = deleteSpec;
     //FromClause = new WFromClause
     //{
     //    TableReferences = new List<WTableReference>
     //    {
     //        new WQueryDerivedTable
     //        {
     //            QueryExpr = deleteSpec
     //        }
     //    }
     //};
     EdgeColumn = deleteSpec.MatchClause.Paths[0].PathEdgeList[0].Item2;
 }
 public WDeleteEdgeSpecification(WSelectQueryBlock deleteSpec)
 {
     SelectDeleteExpr = deleteSpec;
     //FromClause = new WFromClause
     //{
     //    TableReferences = new List<WTableReference>
     //    {
     //        new WQueryDerivedTable
     //        {
     //            QueryExpr = deleteSpec
     //        }
     //    }
     //};
     EdgeColumn = deleteSpec.MatchClause.Paths[0].PathEdgeList[0].Item2;
 }
        public override WTableReference ToTableReference()
        {
            WSelectQueryBlock queryBlock = SubqueryContext.ToSelectQueryBlock();

            queryBlock.SelectElements.Clear();
            if (SubqueryContext.PivotVariable.ProjectedProperties.Count == 0)
            {
                SubqueryContext.PivotVariable.ProjectedProperties.Add(GetProjectKey());
            }

            List <WScalarExpression> foldParameters = new List <WScalarExpression> {
                SubqueryContext.PivotVariable.ToCompose1()
            };

            queryBlock.SelectElements.Add(SqlUtil.GetSelectScalarExpr(SqlUtil.GetFunctionCall(GremlinKeyword.func.Fold, foldParameters), GremlinKeyword.ScalarValue));
            return(SqlUtil.GetDerivedTable(queryBlock, GetVariableName()));
        }
Example #18
0
        public override WTableReference ToTableReference()
        {
            List <WScalarExpression> parameters = new List <WScalarExpression>();

            parameters.Add(SqlUtil.GetValueExpr(this.SideEffectKey));

            WSelectQueryBlock groupBlock = this.GroupByContext.ToSelectQueryBlock(true);

            parameters.Add(SqlUtil.GetScalarSubquery(groupBlock));

            WSelectQueryBlock projectBlock = this.ProjectByContext.ToSelectQueryBlock(true);

            parameters.Add(SqlUtil.GetScalarSubquery(projectBlock));

            var tableRef = SqlUtil.GetFunctionTableReference(GremlinKeyword.func.Group, parameters, GetVariableName());

            ((WGroupTableReference)tableRef).IsProjectingACollection = this.IsProjectingACollection;
            return(SqlUtil.GetCrossApplyTableReference(tableRef));
        }
        public override WTableReference ToTableReference()
        {
            List <WScalarExpression> parameters  = new List <WScalarExpression>();
            List <WSelectQueryBlock> queryBlocks = new List <WSelectQueryBlock>();

            //Must toSelectQueryBlock before toCompose1 of variableList in order to populate needed columns
            foreach (var byContext in ByContexts)
            {
                //TODO: select compose1
                WSelectQueryBlock queryBlock = byContext.ToSelectQueryBlock();
                queryBlock.SelectElements.Clear();
                queryBlock.SelectElements.Add(SqlUtil.GetSelectScalarExpr(byContext.PivotVariable.ToCompose1(), GremlinKeyword.TableDefaultColumnName));
                queryBlocks.Add(queryBlock);
            }

            if (IsInRepeatContext)
            {
                //Must add as the first parameter
                parameters.Add(SqlUtil.GetColumnReferenceExpr(GremlinKeyword.RepeatInitalTableName, GremlinKeyword.Path));
            }
            foreach (var path in PathList)
            {
                if (path.AttachedVariable != null)
                {
                    parameters.Add(SqlUtil.GetColumnReferenceExpr(path.AttachedVariable.GetVariableName(), GremlinKeyword.Path));
                }
                else
                {
                    parameters.Add(path.StepVariable.First().ToCompose1());
                }
            }

            foreach (var block in queryBlocks)
            {
                parameters.Add(SqlUtil.GetScalarSubquery(block));
            }

            var tableRef = SqlUtil.GetFunctionTableReference(GremlinKeyword.func.Path2, parameters, GetVariableName());

            return(SqlUtil.GetCrossApplyTableReference(tableRef));
        }
        public override WTableReference ToTableReference()
        {
            List <WScalarExpression> parameters = new List <WScalarExpression>();

            foreach (var row in rows)
            {
                if (row is string || row is int)
                {
                    var queryBlock = new WSelectQueryBlock();
                    queryBlock.SelectElements.Add(SqlUtil.GetSelectScalarExpr(SqlUtil.GetValueExpr(row), "_value"));
                    parameters.Add(SqlUtil.GetScalarSubquery(queryBlock));
                }
                else
                {
                    throw new NotImplementedException();
                }
            }
            var secondTableRef = SqlUtil.GetFunctionTableReference(GremlinKeyword.func.Inject, parameters, this, GetVariableName());

            return(SqlUtil.GetCrossApplyTableReference(null, secondTableRef));
        }
        public override WTableReference ToTableReference()
        {
            WSelectQueryBlock firstQueryExpr = new WSelectQueryBlock();

            foreach (var projectProperty in ProjectedProperties)
            {
                if (projectProperty == GremlinKeyword.TableDefaultColumnName)
                {
                    firstQueryExpr.SelectElements.Add(SqlUtil.GetSelectScalarExpr(InputVariable.DefaultProjection().ToScalarExpression(),
                                                                                  GremlinKeyword.TableDefaultColumnName));
                }
                else
                if (InputVariable.ProjectedProperties.Contains(projectProperty))
                {
                    firstQueryExpr.SelectElements.Add(
                        SqlUtil.GetSelectScalarExpr(
                            InputVariable.GetVariableProperty(projectProperty).ToScalarExpression(), projectProperty));
                }
                else
                {
                    firstQueryExpr.SelectElements.Add(
                        SqlUtil.GetSelectScalarExpr(SqlUtil.GetValueExpr(null), projectProperty));
                }
            }

            if (OptionalContext.IsPopulateGremlinPath)
            {
                firstQueryExpr.SelectElements.Add(SqlUtil.GetSelectScalarExpr(SqlUtil.GetValueExpr(null), GremlinKeyword.Path));
            }

            WSelectQueryBlock secondQueryExpr = OptionalContext.ToSelectQueryBlock(ProjectedProperties);
            var WBinaryQueryExpression        = SqlUtil.GetBinaryQueryExpr(firstQueryExpr, secondQueryExpr);

            List <WScalarExpression> parameters = new List <WScalarExpression>();

            parameters.Add(SqlUtil.GetScalarSubquery(WBinaryQueryExpression));
            var tableRef = SqlUtil.GetFunctionTableReference(GremlinKeyword.func.Optional, parameters, GetVariableName());

            return(SqlUtil.GetCrossApplyTableReference(tableRef));
        }
        public override WTableReference ToTableReference()
        {
            WSelectQueryBlock queryBlock = SubqueryContext.ToSelectQueryBlock();

            queryBlock.SelectElements.Clear();
            List <WValueExpression> columnListExpr = new List <WValueExpression>();

            foreach (var projectProperty in ProjectedProperties)
            {
                columnListExpr.Add(SqlUtil.GetValueExpr(projectProperty));
            }
            List <WScalarExpression> capParameters = new List <WScalarExpression>();

            foreach (var sideEffectKey in SideEffectKeys)
            {
                capParameters.Add(new WColumnNameList(columnListExpr));
                capParameters.Add(SqlUtil.GetValueExpr(sideEffectKey));
            }

            queryBlock.SelectElements.Add(SqlUtil.GetSelectScalarExpr(SqlUtil.GetFunctionCall(GremlinKeyword.func.Cap, capParameters), GremlinKeyword.ScalarValue));
            return(SqlUtil.GetDerivedTable(queryBlock, GetVariableName()));
        }
Example #23
0
        internal void Split(out WSelectQueryBlock contextSelect, out WSelectQueryBlock repeatSelectQuery)
        {
            WScalarSubquery repeatInput = Parameters[0] as WScalarSubquery;

            if (repeatInput == null)
            {
                throw new SyntaxErrorException("The input of a repeat table reference must be a scalar subquery.");
            }
            WBinaryQueryExpression binaryQuery = repeatInput.SubQueryExpr as WBinaryQueryExpression;

            if (binaryQuery == null || binaryQuery.BinaryQueryExprType != BinaryQueryExpressionType.Union || !binaryQuery.All)
            {
                throw new SyntaxErrorException("The input of a repeat table reference must be a UNION ALL binary query expression.");
            }

            contextSelect     = binaryQuery.FirstQueryExpr as WSelectQueryBlock;
            repeatSelectQuery = binaryQuery.SecondQueryExpr as WSelectQueryBlock;

            if (contextSelect == null || repeatSelectQuery == null)
            {
                throw new SyntaxErrorException("The input of a repeat table reference must be a UNION ALL binary query and the two sub-queries must be a select query block.");
            }
        }
        public override WTableReference ToTableReference()
        {
            List <WScalarExpression> parameters = new List <WScalarExpression>();

            if (this.UnionContextList.Count == 0)
            {
                parameters.AddRange(this.ProjectedProperties.Select(SqlUtil.GetValueExpr));
            }
            else
            {
                foreach (GremlinToSqlContext context in this.UnionContextList)
                {
                    WSelectQueryBlock selectQueryBlock = context.ToSelectQueryBlock();
                    Dictionary <string, WSelectElement> projectionMap = new Dictionary <string, WSelectElement>();
                    WSelectElement value = selectQueryBlock.SelectElements[0];
                    foreach (WSelectElement selectElement in selectQueryBlock.SelectElements)
                    {
                        projectionMap[(selectElement as WSelectScalarExpression).ColumnName] = selectElement;
                    }
                    selectQueryBlock.SelectElements.Clear();

                    selectQueryBlock.SelectElements.Add(SqlUtil.GetSelectScalarExpr((value as WSelectScalarExpression).SelectExpr, this.DefaultProperty()));
                    foreach (string property in this.ProjectedProperties)
                    {
                        selectQueryBlock.SelectElements.Add(
                            projectionMap.TryGetValue(property, out value)
                                ? value : SqlUtil.GetSelectScalarExpr(SqlUtil.GetValueExpr(null), property));
                    }
                    parameters.Add(SqlUtil.GetScalarSubquery(selectQueryBlock));
                }
            }

            var tableRef = SqlUtil.GetFunctionTableReference(GremlinKeyword.func.Union, parameters, GetVariableName());

            return(SqlUtil.GetCrossApplyTableReference(tableRef));
        }
Example #25
0
 public override void Visit(WSelectQueryBlock node)
 {
     UpdateMapping(node);
 }
        /// <summary>
        /// Estimate number of rows of node table in graph.
        /// </summary>
        /// <param name="graph">Constructed node graph</param>
        private void EstimateRows(WSelectQueryBlock query, MatchGraph graph)
        {
            var declareParameter = "";
            if (_variables != null)
            {
                foreach (var parameter in _variables)
                {
                    declareParameter += "DECLARE " + parameter.VariableName.Value + " " +
                                        TsqlFragmentToString.DataType(parameter.DataType) + "\r\n";
                }
            }
            var estimator = new TableSizeEstimator(Conn);
            bool first = true;
            var fromQuerySb = new StringBuilder(1024);
            foreach (var subGraph in graph.ConnectedSubGraphs)
            {
                foreach (var node in subGraph.Nodes)
                {
                    if (first)
                        first = false;
                    else
                        fromQuerySb.Append(", ");
                    var currentNode = node.Value;
                    fromQuerySb.AppendFormat("{0} AS [{1}] WITH (ForceScan)", currentNode.TableObjectName,
                        currentNode.NodeAlias);
                }
            }
            // Attach proper parts of the where clause into the Estimiation Query
            var columnTableMapping = _context.GetColumnTableMapping(_columnsOfNodeTables);
            var attachWhereClauseVisiter = new AttachNodeEdgePredictesVisitor();
            var nodeEstimationWhereClause = attachWhereClauseVisiter.Invoke(query.WhereClause, graph, columnTableMapping);
            string nodeEstimationQuery = string.Format("{0}\r\n SELECT * FROM {1}\r\n", declareParameter,
                fromQuerySb);
            if (nodeEstimationWhereClause.SearchCondition != null)
                nodeEstimationQuery += nodeEstimationWhereClause.ToString();
            var estimateRows = estimator.GetQueryTableEstimatedRows(nodeEstimationQuery);

            foreach (var subGraph in graph.ConnectedSubGraphs)
            {
                // Update Row Estimation for nodes
                foreach (var node in subGraph.Nodes)
                {
                    var currentNode = node.Value;
                    currentNode.EstimatedRows = estimateRows[node.Key];
                    var tableSchema = currentNode.TableObjectName.SchemaIdentifier.Value;
                    var tableName = currentNode.TableObjectName.BaseIdentifier.Value;
                    currentNode.TableRowCount = estimator.GetTableRowCount(tableSchema, tableName);
                }
                }

            // Attach predicates to nodes and edges
            var attachPredicateVisitor = new AttachWhereClauseVisitor();
            attachPredicateVisitor.Invoke(query.WhereClause, graph, columnTableMapping);

        }
Example #27
0
        public override WTableReference ToTableReference()
        {
            Dictionary <GremlinVariableProperty, string> map  = new Dictionary <GremlinVariableProperty, string>();
            Dictionary <GremlinVariableProperty, string> map2 = new Dictionary <GremlinVariableProperty, string>();
            Dictionary <GremlinVariableProperty, string> map3 = new Dictionary <GremlinVariableProperty, string>();
            Dictionary <GremlinVariableProperty, string> map4 = new Dictionary <GremlinVariableProperty, string>();

            WRepeatConditionExpression conditionExpr = GetRepeatConditionExpression();

            List <WSelectScalarExpression> inputSelectList        = GetInputSelectList(ref map);
            List <WSelectScalarExpression> outerSelectList        = GetOuterSelectList(ref map);
            List <WSelectScalarExpression> terminateSelectList    = GetConditionSelectList(ref map2);
            List <WSelectScalarExpression> repeatPathOuterList    = GetRepeatPathOuterVariableList(ref map3);
            List <WSelectScalarExpression> conditionPathOuterList = GetConditionPathOuterVariableList(ref map4);

            WSelectQueryBlock selectQueryBlock = RepeatContext.ToSelectQueryBlock();

            selectQueryBlock.SelectElements.Clear();

            foreach (var selectElement in inputSelectList)
            {
                selectQueryBlock.SelectElements.Add(selectElement);
            }
            foreach (var selectElement in outerSelectList)
            {
                selectQueryBlock.SelectElements.Add(selectElement);
            }
            foreach (var selectElement in terminateSelectList)
            {
                selectQueryBlock.SelectElements.Add(selectElement);
            }
            foreach (var selectElement in repeatPathOuterList)
            {
                selectQueryBlock.SelectElements.Add(selectElement);
            }
            foreach (var selectElement in conditionPathOuterList)
            {
                selectQueryBlock.SelectElements.Add(selectElement);
            }

            WSelectQueryBlock firstQueryExpr = new WSelectQueryBlock();

            foreach (var item in map)
            {
                firstQueryExpr.SelectElements.Add(SqlUtil.GetSelectScalarExpr(item.Key.ToScalarExpression(), item.Value));
            }
            foreach (var item in map2)
            {
                firstQueryExpr.SelectElements.Add(SqlUtil.GetSelectScalarExpr(SqlUtil.GetValueExpr(null), item.Value));
            }
            foreach (var item in map3)
            {
                firstQueryExpr.SelectElements.Add(SqlUtil.GetSelectScalarExpr(item.Key.ToScalarExpression(), item.Value));
            }
            foreach (var item in map4)
            {
                firstQueryExpr.SelectElements.Add(SqlUtil.GetSelectScalarExpr(item.Key.ToScalarExpression(), item.Value));
            }

            //firstQueryExpr.SelectElements.Add(SqlUtil.GetSelectScalarExpr(FirstVariable.DefaultProjection().ToScalarExpression(), GremlinKeyword.TableDefaultColumnName));
            //selectQueryBlock.SelectElements.Add(SqlUtil.GetSelectScalarExpr(RepeatContext.PivotVariable.DefaultProjection().ToScalarExpression(), GremlinKeyword.TableDefaultColumnName));
            foreach (var property in ProjectedProperties)
            {
                if (InputVariable.ProjectedProperties.Contains(property))
                {
                    firstQueryExpr.SelectElements.Add(
                        SqlUtil.GetSelectScalarExpr(
                            InputVariable.GetVariableProperty(property).ToScalarExpression(), property));
                }
                else
                {
                    firstQueryExpr.SelectElements.Add(
                        SqlUtil.GetSelectScalarExpr(SqlUtil.GetValueExpr(null), property));
                }
                if (RepeatContext.PivotVariable.ProjectedProperties.Contains(property))
                {
                    selectQueryBlock.SelectElements.Add(
                        SqlUtil.GetSelectScalarExpr(
                            RepeatContext.PivotVariable.GetVariableProperty(property).ToScalarExpression(), property));
                }
                else
                {
                    selectQueryBlock.SelectElements.Add(
                        SqlUtil.GetSelectScalarExpr(SqlUtil.GetValueExpr(null), property));
                }
            }

            if (SelectedVariableList.Count != 0)
            {
                foreach (var selectedVariableTuple in SelectedVariableList)
                {
                    var columnName       = selectedVariableTuple.Item1;
                    var selectedVariable = selectedVariableTuple.Item2;
                    firstQueryExpr.SelectElements.Add(SqlUtil.GetSelectScalarExpr(SqlUtil.GetValueExpr(null), columnName));

                    List <WScalarExpression> compose2Paramters = new List <WScalarExpression>();
                    compose2Paramters.Add(selectedVariable.RealVariable.ToCompose1());
                    compose2Paramters.Add(SqlUtil.GetColumnReferenceExpr("R", columnName));
                    WFunctionCall compose2 = SqlUtil.GetFunctionCall(GremlinKeyword.func.Compose2, compose2Paramters);
                    selectQueryBlock.SelectElements.Add(SqlUtil.GetSelectScalarExpr(compose2, columnName));
                }
            }

            if (RepeatContext.IsPopulateGremlinPath)
            {
                var columnName   = GremlinKeyword.Path;
                var pathVariable = RepeatContext.CurrentContextPath;
                firstQueryExpr.SelectElements.Add(SqlUtil.GetSelectScalarExpr(SqlUtil.GetValueExpr(null), columnName));
                selectQueryBlock.SelectElements.Add(SqlUtil.GetSelectScalarExpr(pathVariable.DefaultProjection().ToScalarExpression(), columnName));
            }

            var WBinaryQueryExpression = SqlUtil.GetBinaryQueryExpr(firstQueryExpr, selectQueryBlock);


            ModifyColumnNameVisitor newVisitor = new ModifyColumnNameVisitor();

            newVisitor.Invoke(selectQueryBlock, map);
            newVisitor.Invoke(conditionExpr, map2);
            newVisitor.Invoke(selectQueryBlock, map3);
            newVisitor.Invoke(conditionExpr, map4);

            List <WScalarExpression> repeatParameters = new List <WScalarExpression>();

            repeatParameters.Add(SqlUtil.GetScalarSubquery(WBinaryQueryExpression));
            repeatParameters.Add(conditionExpr);
            var secondTableRef = SqlUtil.GetFunctionTableReference(GremlinKeyword.func.Repeat, repeatParameters, this, GetVariableName());

            return(SqlUtil.GetCrossApplyTableReference(null, secondTableRef));
        }
        /// <summary>
        /// Check validity of the match clause
        /// </summary>
        /// <param name="node"></param>
        private void CheckValidity(WSelectQueryBlock node)
        {
            if (node.MatchClause == null)
                return;
            if (node.MatchClause.Paths.All(
                path => path.PathNodeList.All(
                    part => _context.CheckTable(part.Item1.BaseIdentifier.Value) &&
                            IsNodeTable(_context[part.Item1.BaseIdentifier.Value])
                    )
                ))
            {
                foreach (var path in node.MatchClause.Paths)
                {
                    var index = 0;
                    for (var count = path.PathNodeList.Count; index < count; ++index)
                    {
                        var pathNode = path.PathNodeList[index];
                        var table = _context[pathNode.Item1.BaseIdentifier.Value] as WNamedTableReference;
                        var edge =
                            pathNode.Item2.MultiPartIdentifier.Identifiers.Last().Value.ToLower();
                        var nodeTableKey = WNamedTableReference.SchemaNameToTuple(table.TableObjectName);

                        if (_columnsOfNodeTables[nodeTableKey].ContainsKey(edge))
                        {
                            if (
                                _columnsOfNodeTables.Keys.Contains(
                                    new Tuple<string, string>(nodeTableKey.Item1.ToLower(CultureInfo.CurrentCulture),
                                        _columnsOfNodeTables[nodeTableKey][edge].Reference)))
                            {
                                var nextNode = index != count - 1
                                    ? path.PathNodeList[index + 1].Item1
                                    : path.Tail;
                                var getNextTable = _context[nextNode.BaseIdentifier.Value];
                                if (!IsNodeTable(getNextTable))
                                    throw new GraphViewException("Node table expected in MATCH clause");
                                var nextTable = getNextTable as WNamedTableReference;
                                if (nextTable == null ||
                                    !String.Equals(nextTable.TableObjectName.BaseIdentifier.Value,
                                        _columnsOfNodeTables[nodeTableKey][edge].Reference,
                                        StringComparison.CurrentCultureIgnoreCase))
                                {
                                    throw new GraphViewException(String.Format(CultureInfo.CurrentCulture,
                                        "Wrong Reference Table {0}", nextNode.BaseIdentifier.Value));
                                }
                            }
                            else
                            {
                                throw new GraphViewException(String.Format(CultureInfo.CurrentCulture,
                                    "Node Table Referenced by the Edge {0} not exists", edge));
                            }
                        }
                        else
                        {
                            throw new GraphViewException(String.Format(CultureInfo.CurrentCulture,
                                "Edge Column {0} not exists in the Node Table", edge));
                        }
                    }
                }
            }
            else
            {
                throw new GraphViewException("Node table expected in MATCH clause");
            }
        }
 public void Invoke(WSelectQueryBlock node)
 {
     node.Accept(this);
 }
Example #30
0
        public override void Visit(WSelectQueryBlock node)
        {
            base.Visit(node);
            var flag = false;
            for (var i = 0; i < MatchList.Count; ++i)
            {
                if (MatchFlag[i])
                    continue;

                var nextToken = node.LastTokenIndex + 1;
                while (nextToken < Tokens.Count && Tokens[nextToken].TokenType == TSqlTokenType.WhiteSpace)
                    nextToken++;

                var insideBlock = (node.FirstTokenIndex < MatchList[i].FirstTokenIndex &&
                                   (node.LastTokenIndex > MatchList[i].LastTokenIndex ||
                                    nextToken == MatchList[i].FirstTokenIndex));
                if (!insideBlock)
                    continue;

                nextToken = node.FromClause.LastTokenIndex + 1;
                while (nextToken < Tokens.Count && Tokens[nextToken].TokenType == TSqlTokenType.WhiteSpace)
                    nextToken++;
                // match clause should exactly follow FROM clause
                if (node.FromClause.TableReferences == null ||
                    nextToken != MatchList[i].FirstTokenIndex)
                {
                    var token = Tokens[nextToken];
                    _errors.Add(new ParseError(0, token.Offset, token.Line, token.Column,
                        "MATCH clause should exactly follow FROM clause"));
                }

                // if a where/top row filter/group by/having clause exists, it should be followed by a match clause
                if (node.WhereClause.SearchCondition != null &&
                    node.WhereClause.FirstTokenIndex < MatchList[i].LastTokenIndex)
                {
                    var token = Tokens[nextToken];
                    _errors.Add(new ParseError(0, token.Offset, token.Line, token.Column,
                        "WHERE clause should be followed by a MATCH clause"));
                }
                if (node.TopRowFilter != null &&
                    node.TopRowFilter.FirstTokenIndex < MatchList[i].LastTokenIndex)
                {
                    var token = Tokens[nextToken];
                    _errors.Add(new ParseError(0, token.Offset, token.Line, token.Column,
                        "Top row filter should be followed by a MATCH clause"));
                }
                if (node.GroupByClause != null &&
                    node.GroupByClause.FirstTokenIndex < MatchList[i].LastTokenIndex)
                {
                    var token = Tokens[nextToken];
                    _errors.Add(new ParseError(0, token.Offset, token.Line, token.Column,
                        "GROUP BY clause should be followed by a MATCH clause"));
                }
                if (node.HavingClause != null &&
                    node.HavingClause.FirstTokenIndex < MatchList[i].LastTokenIndex)
                {
                    var token = Tokens[nextToken];
                    _errors.Add(new ParseError(0, token.Offset, token.Line, token.Column,
                        "HAVING clause should be followed by a MATCH clause"));
                }
                if (flag)
                {
                    var token = Tokens[nextToken];
                    _errors.Add(new ParseError(0, token.Offset, token.Line, token.Column,
                        "Mutiple MATCH clauses in same query block"));
                }
                if (_errors.Count > 0)
                    return;
                if (node.LastTokenIndex < MatchList[i].FirstTokenIndex)
                {
                    node.LastTokenIndex = MatchList[i].LastTokenIndex;
                }

                flag = true;
                if (node.MatchClause != null && node.MatchClause.Paths != null && node.MatchClause.Paths.Any())
                {
                    foreach (var path in MatchList[i].Paths)
                    {
                        node.MatchClause.Paths.Add(path);
                    }
                }
                else
                {
                    node.MatchClause = MatchList[i];
                }
                MatchFlag[i] = true;
            }
        }
        /// <summary>
        /// Constructs the graph pattern specified by the MATCH clause. 
        /// The graph pattern may consist of multiple fully-connected sub-graphs.
        /// </summary>
        /// <param name="query">The SELECT query block</param>
        /// <returns>A graph object contains all the connected componeents</returns>
        private MatchGraph ConstructGraph(WSelectQueryBlock query)
        {
            if (query == null || query.MatchClause == null)
                return null;

            var unionFind = new UnionFind();
            var edgeColumnToAliasesDict = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
            var pathDictionary = new Dictionary<string, MatchPath>(StringComparer.OrdinalIgnoreCase);
            var matchClause = query.MatchClause;
            var nodes = new Dictionary<string, MatchNode>(StringComparer.OrdinalIgnoreCase);
            var connectedSubGraphs = new List<ConnectedComponent>();
            var subGrpahMap = new Dictionary<string, ConnectedComponent>(StringComparer.OrdinalIgnoreCase);
            var parent = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            unionFind.Parent = parent;

            // Constructs the graph pattern specified by the path expressions in the MATCH clause
            foreach (var path in matchClause.Paths)
            {
                var index = 0;
                MatchEdge preEdge = null;
                for (var count = path.PathEdgeList.Count; index < count; ++index)
                {
                    var currentNodeTableRef = path.PathEdgeList[index].Item1;
                    var currentEdgeColumnRef = path.PathEdgeList[index].Item2;
                    var currentNodeExposedName = currentNodeTableRef.BaseIdentifier.Value;
                    var nextNodeTableRef = index != count - 1
                        ? path.PathEdgeList[index + 1].Item1
                        : path.Tail;
                    var nextNodeExposedName = nextNodeTableRef.BaseIdentifier.Value;
                    var patternNode = nodes.GetOrCreate(currentNodeExposedName);
                    if (patternNode.NodeAlias == null)
                    {
                        patternNode.NodeAlias = currentNodeExposedName;
                        patternNode.Neighbors = new List<MatchEdge>();
                        patternNode.External = false;
                        var nodeTable = _context[currentNodeExposedName] as WNamedTableReference;
                        if (nodeTable != null)
                        {
                            patternNode.NodeTableObjectName = nodeTable.TableObjectName;
                            if (patternNode.NodeTableObjectName.SchemaIdentifier == null)
                                patternNode.NodeTableObjectName.Identifiers.Insert(0, new Identifier {Value = "dbo"});
                        }
                    }

                    string edgeAlias = currentEdgeColumnRef.Alias;
                    if (edgeAlias == null)
                    {
                        var currentEdgeName = currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last().Value;
                        edgeAlias = string.Format("{0}_{1}_{2}", currentNodeExposedName, currentEdgeName,
                            nextNodeExposedName);
                        if (edgeColumnToAliasesDict.ContainsKey(currentEdgeName))
                        {
                            edgeColumnToAliasesDict[currentEdgeName].Add(edgeAlias);
                        }
                        else
                        {
                            edgeColumnToAliasesDict.Add(currentEdgeName, new List<string> { edgeAlias });
                        }
                    }

                    Identifier edgeIdentifier = currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last();
                    string schema = patternNode.NodeTableObjectName.SchemaIdentifier.Value.ToLower();
                    string nodeTableName = patternNode.NodeTableObjectName.BaseIdentifier.Value;
                    string bindTableName =
                        _context.EdgeNodeBinding[
                            new Tuple<string, string>(nodeTableName.ToLower(), edgeIdentifier.Value.ToLower())].ToLower();
                    MatchEdge edge;
                    if (currentEdgeColumnRef.MinLength == 1 && currentEdgeColumnRef.MaxLength == 1)
                    {
                        edge = new MatchEdge
                        {
                            SourceNode = patternNode,
                            EdgeColumn = currentEdgeColumnRef,
                            EdgeAlias = edgeAlias,
                            BindNodeTableObjName =
                                new WSchemaObjectName(
                                    new Identifier {Value = schema},
                                    new Identifier {Value = bindTableName}
                                    ),
                        };
                        _context.AddEdgeReference(edge);
                    }
                    else
                    {
                        MatchPath matchPath = new MatchPath
                        {
                            SourceNode = patternNode,
                            EdgeColumn = currentEdgeColumnRef,
                            EdgeAlias = edgeAlias,
                            BindNodeTableObjName =
                                new WSchemaObjectName(
                                    new Identifier {Value = schema},
                                    new Identifier {Value = bindTableName}
                                    ),
                            MinLength = currentEdgeColumnRef.MinLength,
                            MaxLength = currentEdgeColumnRef.MaxLength,
                            ReferencePathInfo = false,
                            AttributeValueDict = currentEdgeColumnRef.AttributeValueDict
                        };
                        _context.AddEdgeReference(matchPath);
                        pathDictionary[edgeAlias] = matchPath;
                        edge = matchPath;
                    }

                    if (preEdge != null)
                    {
                        preEdge.SinkNode = patternNode;
                    }
                    preEdge = edge;

                    if (!parent.ContainsKey(currentNodeExposedName))
                        parent[currentNodeExposedName] = currentNodeExposedName;
                    if (!parent.ContainsKey(nextNodeExposedName))
                        parent[nextNodeExposedName] = nextNodeExposedName;

                    unionFind.Union(currentNodeExposedName, nextNodeExposedName);


                    patternNode.Neighbors.Add(edge);


                }
                var tailExposedName = path.Tail.BaseIdentifier.Value;
                var tailNode = nodes.GetOrCreate(tailExposedName);
                if (tailNode.NodeAlias == null)
                {
                    tailNode.NodeAlias = tailExposedName;
                    tailNode.Neighbors = new List<MatchEdge>();
                    var nodeTable = _context[tailExposedName] as WNamedTableReference;
                    if (nodeTable != null)
                    {
                        tailNode.NodeTableObjectName = nodeTable.TableObjectName;
                        if (tailNode.NodeTableObjectName.SchemaIdentifier == null)
                            tailNode.NodeTableObjectName.Identifiers.Insert(0, new Identifier {Value = "dbo"});
                    }
                }
                if (preEdge != null)
                    preEdge.SinkNode = tailNode;
            }

            // Puts nodes into subgraphs
            foreach (var node in nodes)
            {
                string root = unionFind.Find(node.Key);
                if (!subGrpahMap.ContainsKey(root))
                {
                    var subGraph = new ConnectedComponent();
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGrpahMap[root] = subGraph;
                    connectedSubGraphs.Add(subGraph);
                    subGraph.IsTailNode[node.Value] = false;
                }
                else
                {
                    var subGraph = subGrpahMap[root];
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGraph.IsTailNode[node.Value] = false;
                }
            }

            var graph = new MatchGraph
            {
                ConnectedSubGraphs = connectedSubGraphs,
            };
            unionFind.Parent = null;

            // When an edge in the MATCH clause is not associated with an alias, 
            // assigns to it a default alias: sourceAlias_EdgeColumnName_sinkAlias. 
            // Also rewrites edge attributes anywhere in the query that can be bound to this default alias. 
            var replaceTableRefVisitor = new ReplaceEdgeReferenceVisitor();
            replaceTableRefVisitor.Invoke(query, edgeColumnToAliasesDict);

            // Rematerializes node tables in the MATCH clause which are defined in the upper-level context
            // and join them with the upper-level table references.
            RematerilizeExtrenalNodeTableReference(query, nodes);

            // Transforms the path reference in the SELECT elements into a 
            // scalar function to display path information.
            TransformPathInfoDisplaySelectElement(query, pathDictionary);

            
            return graph;
        }
        private void TranslateEdgeDelete(WDeleteEdgeSpecification node, List<WSqlStatement> res)
        {
            const string deleteEdgeTableName = "GraphView_DeleteEdgeInternalTable";
            string deleteEdgeTempTable = "DeleteTmp_" + Path.GetRandomFileName().Replace(".", "").Substring(0, 8);

            // Wraps the select statement in a common table expression
            WTableReference sinkTable, sourceTable;
            var deleteCommonTableExpr = ConstructDeleteEdgeSelect(node.SelectDeleteExpr,
                node.EdgeColumn.Alias, deleteEdgeTempTable,
                out sinkTable, out sourceTable);
            var sourceNameTable = sourceTable as WNamedTableReference;
            if (sourceNameTable == null)
                throw new GraphViewException("Source table of DELETE EDGE statement should be a named table reference.");
            var sinkNameTable = sinkTable as WNamedTableReference;
            if (sinkNameTable == null)
                throw new GraphViewException("Sink table of DELETE EDGE statement should be a named table reference.");


            // Get edge select query and reversed edge select query
            WSelectQueryBlock edgeSelectQuery = new WSelectQueryBlock
            {
                SelectElements = new List<WSelectElement>
                {
                    new WSelectScalarExpression
                    {
                        SelectExpr = new WColumnReferenceExpression
                        {
                            MultiPartIdentifier = new WMultiPartIdentifier(new Identifier {Value = "src"})
                        },
                        ColumnName = "source"
                    },
                    new WSelectScalarExpression
                    {
                        SelectExpr = new WFunctionCall
                        {
                            CallTarget = new WMultiPartIdentifierCallTarget
                            {
                                Identifiers = new WMultiPartIdentifier(new Identifier {Value = "dbo"})
                            },
                            FunctionName = new Identifier {Value = GraphViewConnection.GraphViewUdfAssemblyName + "EdgeIdEncoder"},
                            Parameters = new List<WScalarExpression>
                            {
                                new WColumnReferenceExpression
                                {
                                    MultiPartIdentifier = new WMultiPartIdentifier(new Identifier {Value = "edgeid"})
                                },
                            },
                        },
                        ColumnName = "binary1"
                    },
                    new WSelectScalarExpression
                    {
                        SelectExpr = new WFunctionCall
                        {
                            FunctionName = new Identifier{Value = "COUNT"},
                            Parameters = new List<WScalarExpression>
                            {
                                new WColumnReferenceExpression
                                {
                                    MultiPartIdentifier = new WMultiPartIdentifier(new Identifier {Value = "sink"})
                                },
                            },
                        },
                        ColumnName = "sinkCnt"
                    }
                    
                },
                FromClause = new WFromClause
                {
                    TableReferences = new List<WTableReference>
                    {
                        new WSpecialNamedTableReference
                        {
                            TableObjectName = new WSchemaObjectName(new Identifier{Value = deleteEdgeTempTable })
                        }
                    }
                },
                GroupByClause = new WGroupByClause
                {
                    GroupingSpecifications = new List<WGroupingSpecification>
                    {
                        new WExpressionGroupingSpec
                        {
                            Expression = new WValueExpression("src",false)
                        }
                    }
                }
            };
            WSelectQueryBlock reversedEdgeSelectQuery = new WSelectQueryBlock
            {
                SelectElements = new List<WSelectElement>
                {
                    new WSelectScalarExpression
                    {
                        SelectExpr = new WColumnReferenceExpression
                        {
                            MultiPartIdentifier = new WMultiPartIdentifier(new Identifier {Value = "sink"})
                        },
                        ColumnName = "source"
                    },
                    new WSelectScalarExpression
                    {
                        SelectExpr = new WFunctionCall
                        {
                            FunctionName =
                                new Identifier
                                {
                                    Value = "COUNT"
                                },
                            Parameters = new List<WScalarExpression>
                            {
                                new WColumnReferenceExpression
                                {
                                    MultiPartIdentifier = new WMultiPartIdentifier(new Identifier {Value = "src"})
                                },
                            }
                        },
                        ColumnName = "srcCnt"
                    },

                },
                FromClause = edgeSelectQuery.FromClause,
                GroupByClause = new WGroupByClause
                {
                    GroupingSpecifications = new List<WGroupingSpecification>
                    {
                        new WExpressionGroupingSpec
                        {
                            Expression = new WValueExpression("sink", false)
                        }
                    }
                }
            };

            //Check src & sink
            string sourceTableName = sourceNameTable.TableObjectName.ToString();
            string sinkTableName = sinkNameTable.TableObjectName.ToString();
            int compare = string.CompareOrdinal(sourceTableName, sinkTableName);
            WSetClause[] setClauses = new WSetClause[]
            {
                new WFunctionCallSetClause()
                {
                    MutatorFuction = new WFunctionCall
                    {
                        CallTarget = new WMultiPartIdentifierCallTarget()
                        {
                            Identifiers =
                                new WMultiPartIdentifier(new Identifier
                                {
                                    Value = node.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value + "DeleteCol"
                                })
                        },
                        FunctionName = new Identifier {Value = "WRITE"},
                        Parameters = new WScalarExpression[]
                        {
                            new WColumnReferenceExpression
                            {
                                MultiPartIdentifier = new WMultiPartIdentifier(
                                    new Identifier {Value = deleteEdgeTableName},
                                    new Identifier {Value = "binary1"})
                            },
                            new WValueExpression("null", false),
                            new WValueExpression("null", false)
                        }
                    }
                },
                new WAssignmentSetClause()
                {
                    AssignmentKind = AssignmentKind.Equals,
                    Column = new WColumnReferenceExpression
                    {
                        MultiPartIdentifier =
                            new WMultiPartIdentifier(new Identifier
                            {
                                Value = "InDegree"
                            })
                    },
                    NewValue = new WBinaryExpression
                    {
                        FirstExpr = new WColumnReferenceExpression
                        {
                            MultiPartIdentifier =
                                new WMultiPartIdentifier(new Identifier
                                {
                                    Value = "InDegree"
                                })
                        },
                        SecondExpr = new WColumnReferenceExpression
                        {
                            MultiPartIdentifier = new WMultiPartIdentifier(new Identifier {Value = "srcCnt"})
                        },
                        ExpressionType = BinaryExpressionType.Subtract
                    }
                },
                new WAssignmentSetClause()
                {
                    AssignmentKind = AssignmentKind.Equals,
                    Column = new WColumnReferenceExpression
                    {
                        MultiPartIdentifier =
                            new WMultiPartIdentifier(new Identifier
                            {
                                Value = node.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value + "OutDegree"
                            })
                    },
                    NewValue = new WBinaryExpression
                    {
                        FirstExpr = new WColumnReferenceExpression
                        {
                            MultiPartIdentifier =
                                new WMultiPartIdentifier(new Identifier
                                {
                                    Value = node.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value + "OutDegree"
                                })
                        },
                        SecondExpr = new WColumnReferenceExpression
                        {
                            MultiPartIdentifier = new WMultiPartIdentifier(new Identifier {Value = "sinkCnt"})
                        },
                        ExpressionType = BinaryExpressionType.Subtract
                    }
                }
                
            };
            WWhereClause whereClause = new WWhereClause
            {
                SearchCondition = new WBooleanComparisonExpression
                {
                    FirstExpr = new WColumnReferenceExpression
                    {
                        MultiPartIdentifier = new WMultiPartIdentifier(new Identifier { Value = "GlobalNodeId" })
                    },
                    SecondExpr = new WColumnReferenceExpression
                    {
                        MultiPartIdentifier = new WMultiPartIdentifier(
                            new Identifier { Value = deleteEdgeTableName },
                            new Identifier { Value = "source" }
                            )
                    },
                    ComparisonType = BooleanComparisonType.Equals
                }
            };
            if (compare == 0)
            {
                res.Add(new WDeclareTableVariable
                {
                    VariableName = new Identifier { Value = "@" + deleteEdgeTempTable},
                    Definition = new WTableDefinition
                    {
                        ColumnDefinitions = new WColumnDefinition[]
                        {
                            new WColumnDefinition
                            {
                                ColumnIdentifier = new Identifier{Value = "source"},
                                DataType = new WParameterizedDataTypeReference{Name = new WSchemaObjectName(new Identifier{Value = "bigint"})},
                                Constraints = new List<WConstraintDefinition>
                                {
                                    new WUniqueConstraintDefinition
                                    {
                                        Clustered = true,
                                        IsPrimaryKey = true
                                    }
                                }
                            }, 
                            new WColumnDefinition
                            {
                                ColumnIdentifier = new Identifier{Value = "binary1"},
                                DataType = new WParameterizedDataTypeReference
                                {
                                    Name = new WSchemaObjectName(new Identifier{Value = "varbinary"}),
                                    Parameters = new List<Literal>{new MaxLiteral{Value = "max"}}
                                },
                            }, 
                            new WColumnDefinition
                            {
                                ColumnIdentifier = new Identifier{Value = "sinkCnt"},
                                DataType = new WParameterizedDataTypeReference
                                {
                                    Name = new WSchemaObjectName(new Identifier{Value = "int"}),
                                },
                            }, 
                            new WColumnDefinition
                            {
                                ColumnIdentifier = new Identifier{Value = "srcCnt"},
                                DataType = new WParameterizedDataTypeReference
                                {
                                    Name = new WSchemaObjectName(new Identifier{Value = "int"}),
                                },
                            }, 
                        },
                        Indexes = new List<WIndexDefinition>(),
                        TableConstraints = new List<WConstraintDefinition>()
                    }
                });
                var tableVar = new WSpecialNamedTableReference
                {
                    TableObjectName = new WSchemaObjectName(new Identifier { Value = "@" + deleteEdgeTempTable })
                };
                res.Add(deleteCommonTableExpr);
                res.Add(new WInsertSpecification
                {
                    Target = tableVar,
                    InsertSource = new WSelectInsertSource
                    {
                        Select = new WSelectQueryBlock
                        {
                            SelectElements = new WSelectElement[]
                            {
                                new WSelectScalarExpression
                                {
                                    SelectExpr = new WFunctionCall
                                    {
                                        FunctionName = new Identifier {Value = "ISNULL"},
                                        Parameters = new WScalarExpression[]
                                        {
                                            new WColumnReferenceExpression
                                            {
                                                MultiPartIdentifier =
                                                    new WSchemaObjectName(new Identifier[]
                                                    {
                                                        new Identifier {Value = deleteEdgeTableName + "_1"},
                                                        new Identifier {Value = "source"}
                                                    }),
                                            },
                                            new WColumnReferenceExpression
                                            {
                                                MultiPartIdentifier =
                                                    new WSchemaObjectName(new Identifier[]
                                                    {
                                                        new Identifier {Value = deleteEdgeTableName + "_2"},
                                                        new Identifier {Value = "source"}
                                                    }),
                                            },
                                        }
                                    },
                                    ColumnName = "source"
                                },
                                new WSelectScalarExpression
                                {
                                    SelectExpr = new WColumnReferenceExpression
                                    {
                                        MultiPartIdentifier =
                                            new WSchemaObjectName(new Identifier[] {new Identifier {Value = "binary1"}}),
                                    }
                                },
                                //new WSelectScalarExpression
                                //{
                                //    SelectExpr = new WColumnReferenceExpression
                                //    {
                                //                MultiPartIdentifier = new WSchemaObjectName(new Identifier[]{new Identifier{Value = "binary2"}}),
                                //    }
                                //}, 
                                new WSelectScalarExpression
                                {
                                    SelectExpr = new WFunctionCall
                                    {
                                        FunctionName = new Identifier {Value = "ISNULL"},
                                        Parameters = new WScalarExpression[]
                                        {
                                            new WColumnReferenceExpression
                                            {
                                                MultiPartIdentifier =
                                                    new WSchemaObjectName(new Identifier[]
                                                    {
                                                        new Identifier {Value = deleteEdgeTableName + "_1"},
                                                        new Identifier {Value = "sinkCnt"}
                                                    }),
                                            },
                                            new WValueExpression
                                            {
                                                Value = "0"
                                            },
                                        }
                                    },
                                    ColumnName = "sinkCnt"
                                },
                                new WSelectScalarExpression
                                {
                                    SelectExpr = new WFunctionCall
                                    {
                                        FunctionName = new Identifier {Value = "ISNULL"},
                                        Parameters = new WScalarExpression[]
                                        {
                                            new WColumnReferenceExpression
                                            {
                                                MultiPartIdentifier =
                                                    new WSchemaObjectName(new Identifier[]
                                                    {
                                                        new Identifier {Value = deleteEdgeTableName + "_2"},
                                                        new Identifier {Value = "srcCnt"}
                                                    }),
                                            },
                                            new WValueExpression
                                            {
                                                Value = "0"
                                            },
                                        }
                                    },
                                    ColumnName = "srcCnt"
                                },
                            },
                            FromClause = new WFromClause
                            {
                                TableReferences = new WTableReference[]
                                {
                                    new WQualifiedJoin
                                    {
                                        QualifiedJoinType = QualifiedJoinType.FullOuter,
                                        FirstTableRef = new WQueryDerivedTable
                                        {
                                            Alias = new Identifier {Value = deleteEdgeTableName + "_1"},
                                            QueryExpr = edgeSelectQuery
                                        },
                                        SecondTableRef = new WQueryDerivedTable
                                        {
                                            Alias = new Identifier {Value = deleteEdgeTableName + "_2"},
                                            QueryExpr = reversedEdgeSelectQuery
                                        },
                                        JoinCondition = new WBooleanComparisonExpression()
                                        {
                                            ComparisonType = BooleanComparisonType.Equals,
                                            FirstExpr = new WColumnReferenceExpression
                                            {
                                                MultiPartIdentifier =
                                                    new WSchemaObjectName(new Identifier[]
                                                    {
                                                        new Identifier {Value = deleteEdgeTableName + "_1"},
                                                        new Identifier {Value = "source"}
                                                    }),
                                            },
                                            SecondExpr = new WColumnReferenceExpression
                                            {
                                                MultiPartIdentifier =
                                                    new WSchemaObjectName(new Identifier[]
                                                    {
                                                        new Identifier {Value = deleteEdgeTableName + "_2"},
                                                        new Identifier {Value = "source"}
                                                    }),
                                            }
                                        }
                                    },
                                }
                            }
                        }
                    }
                });
                res.Add(new WUpdateSpecification
                {
                    Target = new WNamedTableReference
                    {
                        TableObjectName = sourceNameTable.TableObjectName
                    },
                    SetClauses = setClauses,
                    FromClause = new WFromClause
                    {
                        TableReferences = new WTableReference[]
                        {
                            new WQueryDerivedTable
                            {
                                Alias = new Identifier {Value = deleteEdgeTableName},
                                QueryExpr = new WSelectQueryBlock
                                {
                                    SelectElements = new List<WSelectElement>()
                                    {
                                        new WSelectStarExpression()
                                    },
                                    FromClause = new WFromClause
                                    {
                                        TableReferences = new List<WTableReference> {tableVar}
                                    }
                                }
                            },
                        }
                    },
                    WhereClause = whereClause,
                    TopRowFilter = node.TopRowFilter,
                });
                res.Add(new WSqlUnknownStatement
                {
                    Statement = String.Format("DELETE FROM @{0}", deleteEdgeTempTable)
                });
            }
            else
            {
                // Declare table variables
                res.Add(new WDeclareTableVariable
                {
                    VariableName = new Identifier { Value = "@" + deleteEdgeTempTable + "_1" },
                    Definition = new WTableDefinition
                    {
                        ColumnDefinitions = new WColumnDefinition[]
                        {
                            new WColumnDefinition
                            {
                                ColumnIdentifier = new Identifier {Value = "source"},
                                DataType =
                                    new WParameterizedDataTypeReference
                                    {
                                        Name = new WSchemaObjectName(new Identifier {Value = "bigint"})
                                    },
                                Constraints = new List<WConstraintDefinition>
                                {
                                    new WUniqueConstraintDefinition
                                    {
                                        Clustered = true,
                                        IsPrimaryKey = true
                                    }
                                }
                            },
                            new WColumnDefinition
                            {
                                ColumnIdentifier = new Identifier {Value = "binary1"},
                                DataType = new WParameterizedDataTypeReference
                                {
                                    Name = new WSchemaObjectName(new Identifier {Value = "varbinary"}),
                                    Parameters = new List<Literal> {new MaxLiteral {Value = "max"}}
                                },
                            },
                            new WColumnDefinition
                            {
                                ColumnIdentifier = new Identifier {Value = "sinkCnt"},
                                DataType = new WParameterizedDataTypeReference
                                {
                                    Name = new WSchemaObjectName(new Identifier {Value = "int"}),
                                },
                            },
                        },
                        Indexes = new List<WIndexDefinition>(),
                        TableConstraints = new List<WConstraintDefinition>()
                    }
                });
                res.Add(new WDeclareTableVariable
                {
                    VariableName = new Identifier { Value = "@" + deleteEdgeTempTable + "_2" },
                    Definition = new WTableDefinition
                    {
                        ColumnDefinitions = new WColumnDefinition[]
                        {
                            new WColumnDefinition
                            {
                                ColumnIdentifier = new Identifier {Value = "source"},
                                DataType =
                                    new WParameterizedDataTypeReference
                                    {
                                        Name = new WSchemaObjectName(new Identifier {Value = "bigint"})
                                    },
                                Constraints = new List<WConstraintDefinition>
                                {
                                    new WUniqueConstraintDefinition
                                    {
                                        Clustered = true,
                                        IsPrimaryKey = true
                                    }
                                }
                            },
                            new WColumnDefinition
                            {
                                ColumnIdentifier = new Identifier {Value = "srcCnt"},
                                DataType = new WParameterizedDataTypeReference
                                {
                                    Name = new WSchemaObjectName(new Identifier {Value = "int"}),
                                },
                            },
                        },
                        Indexes = new List<WIndexDefinition>(),
                        TableConstraints = new List<WConstraintDefinition>()
                    }
                });

                var tableVar = new WSpecialNamedTableReference
                {
                    TableObjectName = new WSchemaObjectName(new Identifier { Value = "@" + deleteEdgeTempTable + "_1" })
                };
                var reversedTableVar = new WSpecialNamedTableReference
                {
                    TableObjectName = new WSchemaObjectName(new Identifier { Value = "@" + deleteEdgeTempTable + "_2" })
                };
                WInsertSpecification[] insertStat = new WInsertSpecification[]
                {
                    new WInsertSpecification
                    {
                        Target = tableVar,
                        InsertSource = new WSelectInsertSource
                        {
                            Select = edgeSelectQuery
                        }
                    },
                    new WInsertSpecification
                    {
                        Target = reversedTableVar,
                        InsertSource = new WSelectInsertSource
                        {
                            Select = reversedEdgeSelectQuery
                        }
                    }
                };

                // Update statments for edge and reversed edge
                WUpdateSpecification[] updateStat = new WUpdateSpecification[]
                {
                    new WUpdateSpecification
                    {
                        Target = new WNamedTableReference
                        {
                            TableObjectName = sourceNameTable.TableObjectName
                        },
                        SetClauses = new List<WSetClause> {setClauses[0], setClauses[2]},
                        FromClause = new WFromClause
                        {
                            TableReferences = new WTableReference[]
                            {
                                new WQueryDerivedTable
                                {
                                    QueryExpr = new WSelectQueryBlock
                                    {
                                        SelectElements = new List<WSelectElement>()
                                        {
                                            new WSelectStarExpression()
                                        },
                                        FromClause = new WFromClause
                                        {
                                            TableReferences = new List<WTableReference> {tableVar}
                                        }
                                    },
                                    Alias = new Identifier {Value = deleteEdgeTableName},

                                },
                            }
                        },
                        WhereClause = whereClause,
                        TopRowFilter = node.TopRowFilter
                    },
                    new WUpdateSpecification
                    {
                        Target = new WNamedTableReference
                        {
                            TableObjectName = sinkNameTable.TableObjectName
                        },
                        SetClauses = new List<WSetClause> {setClauses[1]},
                        FromClause = new WFromClause
                        {
                            TableReferences = new WTableReference[]
                            {
                                new WQueryDerivedTable
                                {
                                    Alias = new Identifier {Value = deleteEdgeTableName},
                                    QueryExpr = new WSelectQueryBlock
                                    {
                                        SelectElements = new List<WSelectElement>()
                                        {
                                            new WSelectStarExpression()
                                        },
                                        FromClause = new WFromClause
                                        {
                                            TableReferences = new List<WTableReference> {reversedTableVar}
                                        }
                                    }
                                },
                            }
                        },
                        WhereClause = whereClause,
                        TopRowFilter = node.TopRowFilter
                    },

                };
                bool sourceFirst = compare < 0;
                if (sourceFirst)
                {

                    // With expression
                    res.Add(deleteCommonTableExpr);
                    res.Add(insertStat[0]);
                    res.Add(updateStat[0]);
                    res.Add(new WSqlUnknownStatement
                    {
                        Statement = String.Format("DELETE FROM @{0}_1", deleteEdgeTempTable)
                    });

                    // With expression
                    res.Add(deleteCommonTableExpr);
                    res.Add(insertStat[1]);
                    res.Add(updateStat[1]);
                    res.Add(new WSqlUnknownStatement
                    {
                        Statement = String.Format("DELETE FROM @{0}_2", deleteEdgeTempTable)
                    });
                }
                else
                {

                    // With expression
                    res.Add(deleteCommonTableExpr);
                    res.Add(insertStat[1]);
                    res.Add(updateStat[1]);
                    res.Add(new WSqlUnknownStatement
                    {
                        Statement = String.Format("DELETE FROM @{0}_2", deleteEdgeTempTable)
                    });

                    // With expression
                    res.Add(deleteCommonTableExpr);
                    res.Add(insertStat[0]);
                    res.Add(updateStat[0]);
                    res.Add(new WSqlUnknownStatement
                    {
                        Statement = String.Format("DELETE FROM @{0}_1", deleteEdgeTempTable)
                    });
                }

            }

        }
        private void UpdateMapping(WSelectQueryBlock expr)
        {
            if (expr == null)
            {
                throw new EdgeViewException("Invalid Select Statement in CREATE NODE VIEW");
            }
            if (expr.FromClause.TableReferences.Count != 1)
            {
                throw new EdgeViewException(
                          "Only one node table can be specified in each select statemtn of CREATE NODE VIEW");
            }

            var tableRef = expr.FromClause.TableReferences.First() as WNamedTableReference;

            if (tableRef == null)
            {
                throw new EdgeViewException("Invalid node table");
            }

            var schema = tableRef.TableObjectName.DatabaseIdentifier == null
                ? "dbo"
                : tableRef.TableObjectName.DatabaseIdentifier.Value;

            if (string.Compare(schema, _schema, StringComparison.OrdinalIgnoreCase) != 0)
            {
                throw new NodeViewException("All the node tables should be in the same schema as the node view");
            }

            var tableRefName = tableRef.TableObjectName.SchemaIdentifier.Value;
            var edgeName     = tableRef.TableObjectName.BaseIdentifier.Value;

            _edges.Add(new Tuple <string, string>(tableRefName, edgeName));
            if (_defaultMerge)
            {
                if (expr.SelectElements.Count != 1)
                {
                    throw new EdgeViewException(
                              "Select element in each statement should be consistent to the first statement");
                }
                if (!(expr.SelectElements.First() is WSelectStarExpression))
                {
                    throw new EdgeViewException(
                              "Select element should be '*' for " + tableRefName + "." + edgeName);
                }
            }
            else if (_noAttributes)
            {
                if (expr.SelectElements.Count != 1)
                {
                    throw new EdgeViewException(
                              "Select element in each statement should be consistent to the first statement");
                }
                var element   = expr.SelectElements.First();
                var valueExpr = element as WSelectScalarExpression;
                if (valueExpr == null)
                {
                    throw new EdgeViewException(
                              "Select element should be null for " + tableRefName + "." + edgeName);
                }
                var nullExpr = valueExpr.SelectExpr as WValueExpression;
                if (nullExpr == null || nullExpr.Value.ToLower() != "null")
                {
                    throw new EdgeViewException(
                              "Select element should be null for " + tableRefName + "." + edgeName);
                }
            }
            else if (!_attributeMapping.Any())
            {
                if (expr.SelectElements.Count == 1 && expr.SelectElements.First() is WSelectStarExpression)
                {
                    _defaultMerge = true;
                    return;
                }
                foreach (var selectElement in expr.SelectElements)
                {
                    var scalarElement = selectElement as WSelectScalarExpression;
                    if (scalarElement == null)
                    {
                        throw new EdgeViewException("Invalid select element");
                    }
                    string newColName          = scalarElement.ColumnName;
                    var    oldColRefExpression = scalarElement.SelectExpr as WColumnReferenceExpression;
                    if (oldColRefExpression == null)
                    {
                        var oldColValueExpression = scalarElement.SelectExpr as WValueExpression;
                        if (oldColValueExpression == null)
                        {
                            throw new NodeViewException(
                                      "Each select element should be null or reference to a column");
                        }
                        if (oldColValueExpression.Value.ToLower() != "null")
                        {
                            throw new NodeViewException(
                                      "Each select element should be null or reference to a column");
                        }
                        if (string.IsNullOrEmpty(newColName))
                        {
                            if (expr.SelectElements.Count == 1)
                            {
                                _noAttributes = true;
                                return;
                            }
                            throw new EdgeViewException(
                                      "Column name should be specified for the first select null expression");
                        }
                        _attributeMapping.Add(
                            new Tuple <string, List <Tuple <string, string, string> > >(newColName.ToLower(),
                                                                                        new List <Tuple <string, string, string> >()));
                    }
                    else
                    {
                        string oldColName = oldColRefExpression.MultiPartIdentifier.Identifiers.Last().Value;
                        if (string.IsNullOrEmpty(newColName))
                        {
                            newColName = oldColName;
                        }
                        _attributeMapping.Add(
                            new Tuple <string, List <Tuple <string, string, string> > >(newColName.ToLower(),
                                                                                        new List <Tuple <string, string, string> >
                        {
                            new Tuple <string, string, string>(tableRefName.ToLower(), edgeName.ToLower(),
                                                               oldColName.ToLower())
                        }));
                    }
                    _edgeAttribute.Add(newColName);
                }
            }
            else
            {
                for (int i = 0; i < expr.SelectElements.Count; i++)
                {
                    var scalarElement = expr.SelectElements[i] as WSelectScalarExpression;
                    if (scalarElement == null)
                    {
                        throw new NodeViewException("Invalid select element");
                    }
                    var oldColRefExpression = scalarElement.SelectExpr as WColumnReferenceExpression;
                    if (oldColRefExpression == null)
                    {
                        var oldColValueExpression = scalarElement.SelectExpr as WValueExpression;
                        if (oldColValueExpression == null || oldColValueExpression.Value.ToLower() != "null")
                        {
                            throw new EdgeViewException(
                                      "Each select element should be null or reference to a column");
                        }
                    }
                    else
                    {
                        string oldColName = oldColRefExpression.MultiPartIdentifier.Identifiers.Last().Value;
                        _attributeMapping[i].Item2.Add(new Tuple <string, string, string>(tableRefName.ToLower(),
                                                                                          edgeName.ToLower(),
                                                                                          oldColName.ToLower()));
                    }
                }
            }
            //expr.SelectElements.Add(new WSelectScalarExpression
            //{
            //    SelectExpr =
            //        new WColumnReferenceExpression
            //        {
            //            MultiPartIdentifier = new WMultiPartIdentifier(new Identifier {Value = "Sink"})
            //        }
            //});
            //expr.SelectElements.Add(new WSelectScalarExpression
            //{
            //    SelectExpr =
            //        new WColumnReferenceExpression
            //        {
            //            MultiPartIdentifier = new WMultiPartIdentifier(new Identifier { Value = "Src" })
            //        }
            //});
            //expr.FromClause.TableReferences[0] = new WNamedTableReference
            //{
            //    TableObjectName =
            //        new WSchemaObjectName(new Identifier
            //        {
            //            Value = string.Format("{0}_{1}_{2}_Sampling", schema, tableRefName, edgeName)
            //        })
            //};
        }
Example #34
0
 public virtual void Visit(WSelectQueryBlock node)
 {
     node.AcceptChildren(this);
 }
        private WCommonTableExpression ConstructDeleteEdgeSelect(WSelectQueryBlock node, string edgeAlias, string tempTableName
            ,out WTableReference sinkTable, out WTableReference sourceTable)
        {
            sourceTable = null;
            sinkTable = null;
            var sourceTableScalar = node.SelectElements[0] as WSelectScalarExpression;
            if (sourceTableScalar == null)
                return null;
            var sourceTableColumn = sourceTableScalar.SelectExpr as WColumnReferenceExpression;
            if (sourceTableColumn == null)
                return null;
            var sourceTableName = sourceTableColumn.MultiPartIdentifier.Identifiers.Last().Value;

            var sourceNodeIdExpr = new WColumnReferenceExpression();
            foreach (var identifier in sourceTableColumn.MultiPartIdentifier.Identifiers)
                sourceNodeIdExpr.Add(identifier);
            sourceNodeIdExpr.AddIdentifier("GlobalNodeId");

            var collectVarVisitor = new CollectVariableVisitor();
            var context = collectVarVisitor.Invoke(node);
            if (!context.NodeTableDictionary.Any())
            {
                throw new GraphViewException("Missing From Clause in Delete Edge statement");
            }
            WColumnReferenceExpression sinkNodeIdExpr = null;
            sourceTable = context[sourceTableName];

            var groupByParams = new List<WScalarExpression>();
            for (var index = 1; index < node.SelectElements.Count; ++index)
            {
                var element = node.SelectElements[index] as WSelectScalarExpression;
                if (element == null)
                    return null;
                //sink table
                if (index == 1)
                {
                    var sinkTableColumn = element.SelectExpr as WColumnReferenceExpression;
                    if (sinkTableColumn == null)
                        return null;

                    var sinkTableName = sinkTableColumn.MultiPartIdentifier.Identifiers.Last().Value;
                    sinkTable = context[sinkTableName];

                    sinkNodeIdExpr = new WColumnReferenceExpression();
                    foreach (var identifier in sinkTableColumn.MultiPartIdentifier.Identifiers)
                        sinkNodeIdExpr.Add(identifier);
                    sinkNodeIdExpr.AddIdentifier("GlobalNodeId");
                }
            }

            var sourceNodeId = new WSelectScalarExpression
            {
                SelectExpr = sourceNodeIdExpr,
                ColumnName = "src",
            };
            var sinkNodeId = new WSelectScalarExpression
            {
                SelectExpr = sinkNodeIdExpr,
                ColumnName = "sink"
            };
            var edgeId = new WSelectScalarExpression
            {
                SelectExpr = new WColumnReferenceExpression
                {
                    MultiPartIdentifier = new WMultiPartIdentifier(
                        new Identifier[]
                        {
                            new Identifier {Value = edgeAlias},
                            new Identifier {Value = "Edgeid"}
                        }
                        )
                },
                ColumnName = "edgeid"
            };

            var elements = new List<WSelectElement>
            {
                sourceNodeId,
                sinkNodeId,
                edgeId
            };

            return new WCommonTableExpression
            {
                ExpressionName = new Identifier { Value = tempTableName },
                QueryExpression = new WSelectQueryBlock
                {
                    FromClause = node.FromClause,
                    WhereClause = new WWhereClause
                    {
                        SearchCondition = node.WhereClause.SearchCondition
                    },
                    HavingClause = node.HavingClause,
                    OrderByClause = node.OrderByClause,
                    TopRowFilter = node.TopRowFilter,
                    UniqueRowFilter = node.UniqueRowFilter,
                    SelectElements = elements,
                    MatchClause = node.MatchClause,
                }

            };
        }
Example #36
0
        // Repeat algorithm
        // Firstly, we generate the repeatQueryBlock in order that we can get the initial query
        // Secondly, we generate the inputVariableVistorMap via repeatInputVariable.ProjectedProperties,
        // untilInputVariable.ProjectedProperties, emitInputVariable.ProjectedProperties and ProjectedProperties.
        // Generally, these properties are related to the input every time, but in repeatQueryBlock, these are
        // just related to the input of the first time. Therefore, we need to replace these after.
        // Thirdly, we need to generate the firstQueryExpr and the selectColumnExpr of repeatQueryBlock. Pay
        // attention, we need to repeatQueryBlock again because we need more properties about the output of
        // the last step in repeat-step. These properties are populated in the second step.
        // Fourthly, we use the inputVariableVistorMap to replace the columns in the repeatQueryBlock. But we
        // should not change the columns in path-step. Because if we generate the path in the repeat-step, the
        // path consists of
        //  1. the previous steps before the repeat-step
        //  2. the local path(_path) in the repeat-step
        // Keep in mind that the initial _path is null, the _path includes all steps as long as they are in
        // the repeat-step except for the first input. And the _path after the first pass includes the last step
        // in the repeat-step. So the path must include the two part. That means all columns in path-step should
        // not be replaced. Here, we use the ModifyRepeatInputVariablesVisitor to finish this work. If it visits
        // WPathTableReference, it does nothing, otherwise, it will replace the columns according to the
        // inputVariableVistorMap.
        public override WTableReference ToTableReference()
        {
            //The following two variables are used for manually creating SelectScalarExpression of repeat
            List <WSelectScalarExpression> firstSelectList = new List <WSelectScalarExpression>();
            List <WSelectScalarExpression> secondSelectList = new List <WSelectScalarExpression>();
            WScalarExpression firstSelectColumn, secondSelectColumn, firstExpr, secondExpr;

            // The following map is used to replace columns of the first input to columns of the repeat input
            // such as N_0.id -> R.key_0
            string aliasName;
            Tuple <string, string> key, value;
            Dictionary <Tuple <string, string>, Tuple <string, string> > inputVariableVistorMap =
                new Dictionary <Tuple <string, string>, Tuple <string, string> >();

            // We should generate the syntax tree firstly
            // Some variables will populate ProjectProperty only when we call the ToTableReference function where they appear.
            WRepeatConditionExpression repeatConditionExpr = this.GetRepeatConditionExpression();
            WSelectQueryBlock          repeatQueryBlock    = this.RepeatContext.ToSelectQueryBlock();

            GremlinVariable repeatInputVariable  = this.RepeatContext.VariableList.First();
            GremlinVariable repeatOutputVariable = this.RepeatContext.PivotVariable;
            GremlinVariable realInputVariable    = this.InputVariable.RealVariable;
            GremlinVariable repeatPivotVariable  = this.RepeatContext.PivotVariable;

            // this.DefaultProperty
            key   = new Tuple <string, string>(this.GetVariableName(), this.DefaultProperty());
            value = key;
            inputVariableVistorMap[key] = value;

            key   = new Tuple <string, string>(realInputVariable.GetVariableName(), realInputVariable.DefaultProperty());
            value = new Tuple <string, string>(GremlinKeyword.RepeatInitalTableName, this.DefaultProperty());
            inputVariableVistorMap[key] = value;

            firstExpr  = realInputVariable.DefaultProjection().ToScalarExpression();
            secondExpr = repeatOutputVariable.DefaultProjection().ToScalarExpression();
            firstSelectList.Add(SqlUtil.GetSelectScalarExpr(firstExpr, this.DefaultProperty()));
            secondSelectList.Add(SqlUtil.GetSelectScalarExpr(secondExpr, this.DefaultProperty()));

            foreach (string property in this.ProjectedProperties)
            {
                if (property == GremlinKeyword.Path)
                {
                    firstSelectList.Add(SqlUtil.GetSelectScalarExpr(SqlUtil.GetValueExpr(null), GremlinKeyword.Path));
                    secondSelectList.Add(
                        SqlUtil.GetSelectScalarExpr(
                            this.RepeatContext.ContextLocalPath.DefaultProjection().ToScalarExpression(),
                            GremlinKeyword.Path));
                }
                else
                {
                    key   = new Tuple <string, string>(this.GetVariableName(), property);
                    value = key;
                    inputVariableVistorMap[key] = value;

                    key   = new Tuple <string, string>(realInputVariable.GetVariableName(), property);
                    value = new Tuple <string, string>(GremlinKeyword.RepeatInitalTableName, property);
                    inputVariableVistorMap[key] = value;

                    firstExpr = realInputVariable.ProjectedProperties.Contains(property)
                        ? realInputVariable.GetVariableProperty(property).ToScalarExpression()
                        : SqlUtil.GetValueExpr(null);
                    secondExpr = repeatOutputVariable.ProjectedProperties.Contains(property)
                        ? this.RepeatContext.PivotVariable.GetVariableProperty(property).ToScalarExpression()
                        : SqlUtil.GetValueExpr(null);

                    firstSelectList.Add(SqlUtil.GetSelectScalarExpr(firstExpr, property));
                    secondSelectList.Add(SqlUtil.GetSelectScalarExpr(secondExpr, property));
                }
            }

            // repeatInputVariable.DefaultProperty()
            key = new Tuple <string, string>(repeatInputVariable.GetVariableName(), repeatInputVariable.DefaultProperty());
            if (!inputVariableVistorMap.Keys.Contains(key))
            {
                aliasName = this.GenerateKey();
                value     = new Tuple <string, string>(GremlinKeyword.RepeatInitalTableName, aliasName);
                inputVariableVistorMap[key] = value;

                firstSelectColumn  = repeatInputVariable.DefaultProjection().ToScalarExpression() as WColumnReferenceExpression;
                secondSelectColumn = repeatPivotVariable.DefaultProjection().ToScalarExpression() as WColumnReferenceExpression;
                firstSelectList.Add(SqlUtil.GetSelectScalarExpr(firstSelectColumn, aliasName));
                secondSelectList.Add(SqlUtil.GetSelectScalarExpr(secondSelectColumn, aliasName));
            }
            foreach (string property in repeatInputVariable.ProjectedProperties)
            {
                key = new Tuple <string, string>(repeatInputVariable.GetVariableName(), property);
                if (!inputVariableVistorMap.Keys.Contains(key))
                {
                    aliasName = this.GenerateKey();
                    value     = new Tuple <string, string>(GremlinKeyword.RepeatInitalTableName, aliasName);
                    inputVariableVistorMap[key] = value;

                    firstSelectColumn  = repeatInputVariable.GetVariableProperty(property).ToScalarExpression() as WColumnReferenceExpression;
                    secondSelectColumn = repeatPivotVariable.GetVariableProperty(property).ToScalarExpression() as WColumnReferenceExpression;
                    firstSelectList.Add(SqlUtil.GetSelectScalarExpr(firstSelectColumn, aliasName));
                    secondSelectList.Add(SqlUtil.GetSelectScalarExpr(secondSelectColumn, aliasName));
                }
            }

            if (this.RepeatCondition.TerminationContext != null && this.RepeatCondition.TerminationContext.VariableList.Count > 0)
            {
                GremlinVariable untilInputVariable = this.RepeatCondition.TerminationContext.VariableList.First();

                // untilInputVariable.DefaultProperty()
                key = new Tuple <string, string>(untilInputVariable.GetVariableName(), untilInputVariable.DefaultProperty());
                if (!inputVariableVistorMap.Keys.Contains(key))
                {
                    aliasName = this.GenerateKey();
                    value     = new Tuple <string, string>(GremlinKeyword.RepeatInitalTableName, aliasName);
                    inputVariableVistorMap[key] = value;

                    firstSelectColumn =
                        untilInputVariable.DefaultProjection().ToScalarExpression() as WColumnReferenceExpression;
                    secondSelectColumn =
                        repeatPivotVariable.DefaultProjection().ToScalarExpression() as WColumnReferenceExpression;
                    firstSelectList.Add(SqlUtil.GetSelectScalarExpr(firstSelectColumn, aliasName));
                    secondSelectList.Add(SqlUtil.GetSelectScalarExpr(secondSelectColumn, aliasName));
                }

                foreach (string property in untilInputVariable.ProjectedProperties)
                {
                    key = new Tuple <string, string>(untilInputVariable.GetVariableName(), property);
                    if (!inputVariableVistorMap.Keys.Contains(key))
                    {
                        aliasName = this.GenerateKey();
                        value     = new Tuple <string, string>(GremlinKeyword.RepeatInitalTableName, aliasName);
                        inputVariableVistorMap[key] = value;

                        firstSelectColumn  = untilInputVariable.GetVariableProperty(property).ToScalarExpression() as WColumnReferenceExpression;
                        secondSelectColumn = repeatPivotVariable.GetVariableProperty(property).ToScalarExpression() as WColumnReferenceExpression;
                        firstSelectList.Add(SqlUtil.GetSelectScalarExpr(firstSelectColumn, aliasName));
                        secondSelectList.Add(SqlUtil.GetSelectScalarExpr(secondSelectColumn, aliasName));
                    }
                }
            }

            if (this.RepeatCondition.EmitContext != null && this.RepeatCondition.EmitContext.VariableList.Count > 0)
            {
                GremlinVariable emitInputVariable = this.RepeatCondition.EmitContext.VariableList.First();

                // emitInputVariable.DefaultProperty()
                key = new Tuple <string, string>(emitInputVariable.GetVariableName(), emitInputVariable.DefaultProperty());
                if (!inputVariableVistorMap.Keys.Contains(key))
                {
                    aliasName = this.GenerateKey();
                    value     = new Tuple <string, string>(GremlinKeyword.RepeatInitalTableName, aliasName);
                    inputVariableVistorMap[key] = value;

                    firstSelectColumn =
                        emitInputVariable.DefaultProjection().ToScalarExpression() as WColumnReferenceExpression;
                    secondSelectColumn =
                        repeatPivotVariable.DefaultProjection().ToScalarExpression() as WColumnReferenceExpression;
                    firstSelectList.Add(SqlUtil.GetSelectScalarExpr(firstSelectColumn, aliasName));
                    secondSelectList.Add(SqlUtil.GetSelectScalarExpr(secondSelectColumn, aliasName));
                }

                foreach (string property in emitInputVariable.ProjectedProperties)
                {
                    key = new Tuple <string, string>(emitInputVariable.GetVariableName(), property);
                    if (!inputVariableVistorMap.Keys.Contains(key))
                    {
                        aliasName = this.GenerateKey();
                        value     = new Tuple <string, string>(GremlinKeyword.RepeatInitalTableName, aliasName);
                        inputVariableVistorMap[key] = value;

                        firstSelectColumn =
                            emitInputVariable.GetVariableProperty(property).ToScalarExpression() as WColumnReferenceExpression;
                        secondSelectColumn =
                            repeatPivotVariable.GetVariableProperty(property).ToScalarExpression() as WColumnReferenceExpression;
                        firstSelectList.Add(SqlUtil.GetSelectScalarExpr(firstSelectColumn, aliasName));
                        secondSelectList.Add(SqlUtil.GetSelectScalarExpr(secondSelectColumn, aliasName));
                    }
                }
            }

            WSelectQueryBlock firstQueryExpr = new WSelectQueryBlock();

            foreach (WSelectScalarExpression selectColumnExpr in firstSelectList)
            {
                firstQueryExpr.SelectElements.Add(selectColumnExpr);
            }

            repeatQueryBlock = this.RepeatContext.ToSelectQueryBlock();
            repeatQueryBlock.SelectElements.Clear();
            foreach (WSelectScalarExpression selectColumnExpr in secondSelectList)
            {
                repeatQueryBlock.SelectElements.Add(selectColumnExpr);
            }

            //Then we will use the inputVariableVistorMap to replace ColumnRefernceExpression in the syntax tree
            //which matchs n_0.id to R_0.key_0 except for WPathTableReference
            new ModifyRepeatInputVariablesVisitor().Invoke(repeatQueryBlock, inputVariableVistorMap);
            new ModifyRepeatInputVariablesVisitor().Invoke(repeatConditionExpr, inputVariableVistorMap);

            List <WScalarExpression> repeatParameters = new List <WScalarExpression>()
            {
                SqlUtil.GetScalarSubquery(SqlUtil.GetBinaryQueryExpr(firstQueryExpr, repeatQueryBlock)),
                repeatConditionExpr
            };
            WSchemaObjectFunctionTableReference tableRef = SqlUtil.GetFunctionTableReference(GremlinKeyword.func.Repeat, repeatParameters, this.GetVariableName());

            return(SqlUtil.GetCrossApplyTableReference(tableRef));
        }
Example #37
0
        private void UpdateMapping(WSelectQueryBlock expr)
        {
            if (expr == null)
                throw new EdgeViewException("Invalid Select Statement in CREATE NODE VIEW");
            if (expr.FromClause.TableReferences.Count != 1)
                throw new EdgeViewException(
                    "Only one node table can be specified in each select statemtn of CREATE NODE VIEW");

            var tableRef = expr.FromClause.TableReferences.First() as WNamedTableReference;
            if (tableRef == null)
                throw new EdgeViewException("Invalid node table");

            var schema = tableRef.TableObjectName.DatabaseIdentifier == null
                ? "dbo"
                : tableRef.TableObjectName.DatabaseIdentifier.Value;
            if (string.Compare(schema, _schema, StringComparison.OrdinalIgnoreCase) != 0)
                throw new NodeViewException("All the node tables should be in the same schema as the node view");

            var tableRefName = tableRef.TableObjectName.SchemaIdentifier.Value;
            var edgeName = tableRef.TableObjectName.BaseIdentifier.Value;
            _edges.Add(new Tuple<string, string>(tableRefName, edgeName));
            if (_defaultMerge)
            {
                if (expr.SelectElements.Count != 1)
                    throw new EdgeViewException(
                        "Select element in each statement should be consistent to the first statement");
                if (!(expr.SelectElements.First() is WSelectStarExpression))
                    throw new EdgeViewException(
                        "Select element should be '*' for " + tableRefName + "." + edgeName);
            }
            else if (_noAttributes)
            {
                 if (expr.SelectElements.Count != 1)
                     throw new EdgeViewException(
                        "Select element in each statement should be consistent to the first statement");
                var element = expr.SelectElements.First();
                var valueExpr = element as WSelectScalarExpression;
                if (valueExpr == null)
                    throw new EdgeViewException(
                        "Select element should be null for " + tableRefName + "." + edgeName);
                var nullExpr = valueExpr.SelectExpr as WValueExpression;
                if (nullExpr == null || nullExpr.Value.ToLower()!="null")
                    throw new EdgeViewException(
                        "Select element should be null for " + tableRefName + "." + edgeName);
            }
            else if (!_attributeMapping.Any())
            {
                if (expr.SelectElements.Count == 1 && expr.SelectElements.First() is WSelectStarExpression)
                {
                    _defaultMerge = true;
                    return;
                }
                foreach (var selectElement in expr.SelectElements)
                {
                    var scalarElement = selectElement as WSelectScalarExpression;
                    if (scalarElement == null)
                        throw new EdgeViewException("Invalid select element");
                    string newColName = scalarElement.ColumnName;
                    var oldColRefExpression = scalarElement.SelectExpr as WColumnReferenceExpression;
                    if (oldColRefExpression == null)
                    {
                        var oldColValueExpression = scalarElement.SelectExpr as WValueExpression;
                        if (oldColValueExpression == null)
                            throw new NodeViewException(
                                "Each select element should be null or reference to a column");
                        if (oldColValueExpression.Value.ToLower() != "null")
                            throw new NodeViewException(
                                "Each select element should be null or reference to a column");
                        if (string.IsNullOrEmpty(newColName))
                        {
                            if (expr.SelectElements.Count == 1)
                            {
                                _noAttributes = true;
                                return;
                            }
                            throw new EdgeViewException(
                                "Column name should be specified for the first select null expression");
                        }
                        _attributeMapping.Add(
                            new Tuple<string, List<Tuple<string, string, string>>>(newColName.ToLower(),
                                new List<Tuple<string, string, string>>()));
                    }
                    else
                    {
                        string oldColName = oldColRefExpression.MultiPartIdentifier.Identifiers.Last().Value;
                        if (string.IsNullOrEmpty(newColName))
                            newColName = oldColName;
                        _attributeMapping.Add(
                            new Tuple<string, List<Tuple<string, string, string>>>(newColName.ToLower(),
                                new List<Tuple<string, string, string>>
                                {
                                    new Tuple<string, string, string>(tableRefName.ToLower(), edgeName.ToLower(),
                                        oldColName.ToLower())
                                }));
                    }
                    _edgeAttribute.Add(newColName);
                }
            }
            else
            {
                for (int i = 0; i < expr.SelectElements.Count; i++)
                {
                    var scalarElement = expr.SelectElements[i] as WSelectScalarExpression;
                    if (scalarElement == null)
                        throw new NodeViewException("Invalid select element");
                    var oldColRefExpression = scalarElement.SelectExpr as WColumnReferenceExpression;
                    if (oldColRefExpression == null)
                    {
                        var oldColValueExpression = scalarElement.SelectExpr as WValueExpression;
                        if (oldColValueExpression == null || oldColValueExpression.Value.ToLower() != "null")
                            throw new EdgeViewException(
                                "Each select element should be null or reference to a column");
                    }
                    else
                    {
                        string oldColName = oldColRefExpression.MultiPartIdentifier.Identifiers.Last().Value;
                        _attributeMapping[i].Item2.Add(new Tuple<string, string, string>(tableRefName.ToLower(),
                            edgeName.ToLower(),
                            oldColName.ToLower()));
                    }
                }
            }
            //expr.SelectElements.Add(new WSelectScalarExpression
            //{
            //    SelectExpr =
            //        new WColumnReferenceExpression
            //        {
            //            MultiPartIdentifier = new WMultiPartIdentifier(new Identifier {Value = "Sink"})
            //        }
            //});
            //expr.SelectElements.Add(new WSelectScalarExpression
            //{
            //    SelectExpr =
            //        new WColumnReferenceExpression
            //        {
            //            MultiPartIdentifier = new WMultiPartIdentifier(new Identifier { Value = "Src" })
            //        }
            //});
            //expr.FromClause.TableReferences[0] = new WNamedTableReference
            //{
            //    TableObjectName =
            //        new WSchemaObjectName(new Identifier
            //        {
            //            Value = string.Format("{0}_{1}_{2}_Sampling", schema, tableRefName, edgeName)
            //        })
            //};
        }
        private WMultiCommonTableExpression ConstructDeleteEdgeSelect(WSelectQueryBlock node, WEdgeColumnReferenceExpression edgeCol, string tempTableName
            ,out WTableReference sinkTable, out WTableReference sourceTable, ref bool hasReversedEdge)
        {
            sourceTable = null;
            sinkTable = null;
            string sourceTableName = null;
            string sinkTableName = null;
            var sourceTableScalar = node.SelectElements[0] as WSelectScalarExpression;
            if (sourceTableScalar == null)
                return null;
            var sourceTableColumn = sourceTableScalar.SelectExpr as WColumnReferenceExpression;
            if (sourceTableColumn == null)
                return null;
            sourceTableName = sourceTableColumn.MultiPartIdentifier.Identifiers.Last().Value;

            var sourceNodeIdExpr = new WColumnReferenceExpression();
            foreach (var identifier in sourceTableColumn.MultiPartIdentifier.Identifiers)
                sourceNodeIdExpr.Add(identifier);
            sourceNodeIdExpr.AddIdentifier("GlobalNodeId");

            var collectVarVisitor = new CollectVariableVisitor();
            var context = collectVarVisitor.Invoke(node);
            if (!context.NodeTableDictionary.Any())
            {
                throw new GraphViewException("Missing From Clause in Delete Edge statement");
            }
            WColumnReferenceExpression sinkNodeIdExpr = null;
            sourceTable = context[sourceTableName];

            var groupByParams = new List<WScalarExpression>();
            for (var index = 1; index < node.SelectElements.Count; ++index)
            {
                var element = node.SelectElements[index] as WSelectScalarExpression;
                if (element == null)
                    return null;
                //sink table
                if (index == 1)
                {
                    var sinkTableColumn = element.SelectExpr as WColumnReferenceExpression;
                    if (sinkTableColumn == null)
                        return null;

                    sinkTableName = sinkTableColumn.MultiPartIdentifier.Identifiers.Last().Value;
                    sinkTable = context[sinkTableName];

                    sinkNodeIdExpr = new WColumnReferenceExpression();
                    foreach (var identifier in sinkTableColumn.MultiPartIdentifier.Identifiers)
                        sinkNodeIdExpr.Add(identifier);
                    sinkNodeIdExpr.AddIdentifier("GlobalNodeId");
                }
            }

            var sourceNodeId = new WSelectScalarExpression
            {
                SelectExpr = sourceNodeIdExpr,
                ColumnName = "src",
            };
            var sinkNodeId = new WSelectScalarExpression
            {
                SelectExpr = sinkNodeIdExpr,
                ColumnName = "sink"
            };
            var edgeId = new WSelectScalarExpression
            {
                SelectExpr = new WColumnReferenceExpression
                {
                    MultiPartIdentifier = new WMultiPartIdentifier(
                        new Identifier[]
                        {
                            new Identifier {Value = edgeCol.Alias??string.Format("{0}_{1}_{2}",sourceTableName,edgeCol.MultiPartIdentifier.Identifiers.Last().Value,sinkTableName)},
                            new Identifier {Value = "Edgeid"}
                        })
                },
                ColumnName = "edgeid"
            };

            var sourceTableNameRef = sourceTable as WNamedTableReference;
            if (sourceTableNameRef == null)
                throw new GraphViewException("Source table of DELETE EDGE statement should be a named table reference.");
            var sinkTableNameRef = sinkTable as WNamedTableReference;
            if (sinkTableNameRef == null)
                throw new GraphViewException("Sink table of DELETE EDGE statement should be a named table reference.");
            int compare = string.CompareOrdinal(sourceTableNameRef.TableObjectName.ToString(), sinkTableNameRef.TableObjectName.ToString());

            using (var command = Tx.Connection.CreateCommand())
            {
                command.Transaction = Tx;
                command.Parameters.AddWithValue("@schema", WNamedTableReference.SchemaNameToTuple(sourceTableNameRef.TableObjectName).Item1);
                command.Parameters.AddWithValue("@tableName", sourceTableNameRef.TableObjectName.Identifiers.Last().Value);
                command.Parameters.AddWithValue("@colName", edgeCol.MultiPartIdentifier.Identifiers.Last().Value);
                command.Parameters.AddWithValue("@role", WNodeTableColumnRole.Edge);
                command.CommandText = string.Format(@"
                    SELECT NodeColumn.HasReversedEdge
                    FROM [{0}] AS NodeColumn
                    WHERE NodeColumn.TableSchema = @schema and
                          NodeColumn.TableName = @tableName and
                          NodeColumn.ColumnName = @colName and
                          NodeColumn.ColumnRole = @role",
                    GraphViewConnection.MetadataTables[1]);
                using (var reader = command.ExecuteReader())
                {
                    if (reader.Read())
                    {
                        hasReversedEdge = bool.Parse(reader[0].ToString());
                    }
                }
            }

            var reversedEdgeName = sourceTableNameRef.TableObjectName.Identifiers.Last().Value +
                                    "_" + edgeCol.MultiPartIdentifier.Identifiers.Last().Value + "Reversed";
            var reversedEdgeId = new WSelectScalarExpression
            {
                SelectExpr = new WColumnReferenceExpression
                {
                    MultiPartIdentifier = new WMultiPartIdentifier(
                        new Identifier[]
                        {
                            new Identifier {Value = edgeCol.Alias??string.Format("{0}_{1}_{2}",sourceTableName,edgeCol.MultiPartIdentifier.Identifiers.Last().Value,sinkTableName)},
                            new Identifier {Value = "Edgeid"}
                        })
                },
                ColumnName = "edgeid"
            };

            var elements = new List<WSelectElement>
            {
                sourceNodeId,
                sinkNodeId,
                edgeId
            };

            var reversedElements = new List<WSelectElement>
            {
                sourceNodeId,
                sinkNodeId,
                reversedEdgeId,
            };

            return new WMultiCommonTableExpression
            {
                WCommonTableExpressions = new List<WCommonTableExpression>()
                {
                    new WCommonTableExpression
                    {
                        ExpressionName = new Identifier
                        {
                            Value = hasReversedEdge && compare == 0 ? tempTableName + "_1" : tempTableName
                        },
                        QueryExpression = new WSelectQueryBlock
                        {
                            FromClause = node.FromClause,
                            WhereClause = new WWhereClause
                            {
                                SearchCondition = node.WhereClause.SearchCondition
                            },
                            HavingClause = node.HavingClause,
                            OrderByClause = node.OrderByClause,
                            TopRowFilter = node.TopRowFilter,
                            UniqueRowFilter = node.UniqueRowFilter,
                            SelectElements = elements,
                            MatchClause = node.MatchClause,
                        }
                    },
                    new WCommonTableExpression
                    {
                        ExpressionName = new Identifier
                        {
                            Value = hasReversedEdge && compare == 0 ? tempTableName + "_2" : tempTableName
                        },
                        QueryExpression = new WSelectQueryBlock
                        {
                            FromClause = node.FromClause,
                            WhereClause = hasReversedEdge ?
                                new WWhereClause { SearchCondition = ObjectExtensions.Copy(node.WhereClause.SearchCondition), }
                                : node.WhereClause,
                            HavingClause = node.HavingClause,
                            OrderByClause = node.OrderByClause,
                            TopRowFilter = node.TopRowFilter,
                            UniqueRowFilter = node.UniqueRowFilter,
                            SelectElements = hasReversedEdge ? reversedElements : elements,
                            MatchClause = hasReversedEdge? ConstructReversedMatchClause(node, context) : node.MatchClause,
                        }
                    },
                }
            };
        }
        public override WTableReference ToTableReference()
        {
            if (RepeatContext.ContextLocalPath != null)
            {
                RepeatContext.ContextLocalPath.PathList.Insert(0, null);
                RepeatContext.ContextLocalPath.IsInRepeatContext = true;
            }

            //The following two variables are used for manually creating SelectScalarExpression of repeat
            List <WSelectScalarExpression> repeatFirstSelect  = new List <WSelectScalarExpression>();
            List <WSelectScalarExpression> repeatSecondSelect = new List <WSelectScalarExpression>();

            // The following two variables are used for Generating a Map
            // such as N_0.id -> key_0
            // Then we will use this map to replace ColumnRefernceExpression in the syntax tree which matchs n_0.id to R_0.key_0
            Dictionary <WColumnReferenceExpression, string> repeatVistorMap    = new Dictionary <WColumnReferenceExpression, string>();
            Dictionary <WColumnReferenceExpression, string> conditionVistorMap = new Dictionary <WColumnReferenceExpression, string>();

            //We should generate the syntax tree firstly
            //Some variables will populate ProjectProperty only when we call the ToTableReference function where they appear.
            WRepeatConditionExpression repeatConditionExpr = GetRepeatConditionExpression();
            WSelectQueryBlock          repeatQueryBlock    = RepeatContext.ToSelectQueryBlock();

            // TODO: explain this step in detail
            var repeatNewToOldSelectedVarMap = GetNewToOldSelectedVarMap(RepeatContext);

            if (!repeatNewToOldSelectedVarMap.ContainsKey(RepeatContext.PivotVariable))
            {
                repeatNewToOldSelectedVarMap[RepeatContext.PivotVariable] = RepeatContext.VariableList.First();
            }
            foreach (var pair in repeatNewToOldSelectedVarMap)
            {
                GremlinVariable newVariable = pair.Key;
                GremlinVariable oldVariable = pair.Value;
                foreach (var property in pair.Value.ProjectedProperties)
                {
                    var aliasName          = GenerateKey();
                    var firstSelectColumn  = oldVariable.GetVariableProperty(property).ToScalarExpression() as WColumnReferenceExpression;
                    var secondSelectColumn = newVariable.GetVariableProperty(property).ToScalarExpression() as WColumnReferenceExpression;

                    repeatFirstSelect.Add(SqlUtil.GetSelectScalarExpr(firstSelectColumn, aliasName));
                    repeatSecondSelect.Add(SqlUtil.GetSelectScalarExpr(secondSelectColumn, aliasName));
                    repeatVistorMap[firstSelectColumn.Copy()] = aliasName;
                }
            }

            if (RepeatCondition.TerminationContext != null && RepeatCondition.TerminationContext.VariableList.Count > 0)
            {
                var terminatedNewToOldSelectedVarMap = GetNewToOldSelectedVarMap(RepeatCondition.TerminationContext);
                if (!terminatedNewToOldSelectedVarMap.ContainsKey(RepeatContext.PivotVariable))
                {
                    terminatedNewToOldSelectedVarMap[RepeatContext.PivotVariable] = RepeatCondition.TerminationContext.VariableList.First();
                }
                foreach (var pair in terminatedNewToOldSelectedVarMap)
                {
                    GremlinVariable newVariable = pair.Key;
                    GremlinVariable oldVariable = pair.Value;
                    foreach (var property in oldVariable.ProjectedProperties)
                    {
                        var aliasName         = GenerateKey();
                        var firstSelectColumn = RepeatCondition.StartFromContext
                            ? oldVariable.GetVariableProperty(property).ToScalarExpression()
                            : SqlUtil.GetValueExpr(null);
                        var secondSelectColumn = newVariable.GetVariableProperty(property).ToScalarExpression() as WColumnReferenceExpression;

                        repeatFirstSelect.Add(SqlUtil.GetSelectScalarExpr(firstSelectColumn, aliasName));
                        repeatSecondSelect.Add(SqlUtil.GetSelectScalarExpr(secondSelectColumn, aliasName));

                        if (RepeatCondition.StartFromContext)
                        {
                            conditionVistorMap[(firstSelectColumn as WColumnReferenceExpression).Copy()] = aliasName;
                        }
                        else
                        {
                            conditionVistorMap[secondSelectColumn.Copy()] = aliasName;
                        }
                    }
                }
            }

            if (RepeatCondition.EmitContext != null && RepeatCondition.EmitContext.VariableList.Count > 0)
            {
                var terminatedNewToOldSelectedVarMap = GetNewToOldSelectedVarMap(RepeatCondition.EmitContext);
                if (!terminatedNewToOldSelectedVarMap.ContainsKey(RepeatContext.PivotVariable))
                {
                    terminatedNewToOldSelectedVarMap[RepeatContext.PivotVariable] = RepeatCondition.EmitContext.VariableList.First();
                }
                foreach (var pair in terminatedNewToOldSelectedVarMap)
                {
                    GremlinVariable newVariable = pair.Key;
                    GremlinVariable oldVariable = pair.Value;
                    foreach (var property in pair.Value.ProjectedProperties)
                    {
                        var aliasName         = GenerateKey();
                        var firstSelectColumn = RepeatCondition.IsEmitContext
                            ? oldVariable.GetVariableProperty(property).ToScalarExpression()
                            : SqlUtil.GetValueExpr(null);
                        var secondSelectColumn = newVariable.GetVariableProperty(property).ToScalarExpression() as WColumnReferenceExpression;

                        repeatFirstSelect.Add(SqlUtil.GetSelectScalarExpr(firstSelectColumn, aliasName));
                        repeatSecondSelect.Add(SqlUtil.GetSelectScalarExpr(secondSelectColumn, aliasName));

                        if (RepeatCondition.IsEmitContext)
                        {
                            conditionVistorMap[(firstSelectColumn as WColumnReferenceExpression).Copy()] = aliasName;
                        }
                        else
                        {
                            conditionVistorMap[secondSelectColumn.Copy()] = aliasName;
                        }
                    }
                }
            }

            foreach (var property in ProjectedProperties)
            {
                if (property == GremlinKeyword.Path)
                {
                    repeatFirstSelect.Add(SqlUtil.GetSelectScalarExpr(SqlUtil.GetValueExpr(null), GremlinKeyword.Path));
                    repeatSecondSelect.Add(SqlUtil.GetSelectScalarExpr(RepeatContext.ContextLocalPath.GetDefaultProjection().ToScalarExpression(), GremlinKeyword.Path));
                    continue;
                }
                WScalarExpression firstExpr = InputVariable.ProjectedProperties.Contains(property)
                    ? InputVariable.GetVariableProperty(property).ToScalarExpression()
                    : SqlUtil.GetValueExpr(null);

                WScalarExpression secondExpr = RepeatContext.PivotVariable.ProjectedProperties.Contains(property)
                    ? RepeatContext.PivotVariable.GetVariableProperty(property).ToScalarExpression()
                    : SqlUtil.GetValueExpr(null);

                repeatFirstSelect.Add(SqlUtil.GetSelectScalarExpr(firstExpr, property));
                repeatSecondSelect.Add(SqlUtil.GetSelectScalarExpr(secondExpr, property));
            }

            WSelectQueryBlock firstQueryExpr = new WSelectQueryBlock();

            foreach (var selectColumnExpr in repeatFirstSelect)
            {
                firstQueryExpr.SelectElements.Add(selectColumnExpr);
            }

            repeatQueryBlock = RepeatContext.ToSelectQueryBlock();
            repeatQueryBlock.SelectElements.Clear();
            foreach (var selectColumnExpr in repeatSecondSelect)
            {
                repeatQueryBlock.SelectElements.Add(selectColumnExpr);
            }

            //Replace N_0.id -> R_0.key_0, when N_0 is a outer variable
            new ModifyColumnNameVisitor().Invoke(repeatQueryBlock, repeatVistorMap);
            new ModifyColumnNameVisitor().Invoke(repeatConditionExpr, conditionVistorMap);

            List <WScalarExpression> repeatParameters = new List <WScalarExpression>()
            {
                SqlUtil.GetScalarSubquery(SqlUtil.GetBinaryQueryExpr(firstQueryExpr, repeatQueryBlock)),
                repeatConditionExpr
            };
            var tableRef = SqlUtil.GetFunctionTableReference(GremlinKeyword.func.Repeat, repeatParameters, GetVariableName());

            return(SqlUtil.GetCrossApplyTableReference(tableRef));
        }
        private WMatchClause ConstructReversedMatchClause(WSelectQueryBlock node, WSqlTableContext context)
        {
            var result = new WMatchClause()
            {
                Paths = new List<WMatchPath>(),
            };

            foreach (var path in node.MatchClause.Paths)
            {
                var reversedEdgeNameList = new List<string>();
                var nodeList = new List<Tuple<WSchemaObjectName, WEdgeColumnReferenceExpression>>();
                var edgeList = path.PathEdgeList;

                for (var i = 0; i < edgeList.Count; ++i)
                {
                    var sourceTableName = edgeList[i].Item1.Identifiers.Last().Value;
                    var edgeName = edgeList[i].Item2.MultiPartIdentifier.Identifiers.Last().Value;
                    WTableReference sourceTable = context[sourceTableName];
                    var sourceTableObjectName =
                        (sourceTable as WNamedTableReference).TableObjectName.Identifiers.Last().Value;

                    reversedEdgeNameList.Add(sourceTableObjectName + "_" + edgeName + "Reversed");
                }

                var sinkIdentifier = path.Tail.Identifiers.Last();

                for (var i = edgeList.Count - 1; i >= 0; --i)
                {
                    var nodeName = new WSchemaObjectName()
                    {
                        Identifiers = new List<Identifier>
                        {
                            new Identifier()
                            {
                                Value = sinkIdentifier.Value,
                                QuoteType = sinkIdentifier.QuoteType,
                            }
                        },
                    };

                    var originalPath = edgeList[i].Item2;
                    var edgeCol = new WEdgeColumnReferenceExpression()
                    {
                        ColumnType = ColumnType.Regular,
                        Alias = originalPath.Alias,
                        MaxLength = originalPath.MaxLength,
                        MinLength = originalPath.MinLength,
                        AttributeValueDict = originalPath.AttributeValueDict,
                        MultiPartIdentifier = new WMultiPartIdentifier(new Identifier()
                        {
                            QuoteType = originalPath.MultiPartIdentifier.Identifiers.Last().QuoteType,
                            Value = reversedEdgeNameList[i],
                        }),
                    };

                    nodeList.Add(new Tuple<WSchemaObjectName, WEdgeColumnReferenceExpression>(nodeName, edgeCol));
                    sinkIdentifier = edgeList[i].Item1.Identifiers.Last();
                }

                result.Paths.Add(new WMatchPath
                                 {
                                     PathEdgeList = nodeList,
                                     Tail = edgeList[0].Item1,
                                     IsReversed = true,
                                 });
            }

            return result;
        }
 /// <summary>
 /// Marks the node table alias, if it has no outgoing edges in the graph pattern
 /// and its node properties are never referenced or projected in the query.
 /// Such node table aliases will not appear in the FROM clause in the translated
 /// query, but only be materialized in adjacency lists, i.e., table-valued functions.
 /// </summary>
 /// <param name="query"></param>
 /// <param name="graph"></param>
 private void OptimizeTail(WSelectQueryBlock query, MatchGraph graph)
 {
     var visitor = new CheckTableReferenceVisitor();
     foreach (var connectedSubGraph in graph.ConnectedSubGraphs)
     {
         var toRemove = connectedSubGraph.Nodes.Where(
             node => node.Value.Neighbors.Count == 0 &&
                     !visitor.Invoke(query, node.Key, _context, _graphMetaData.ColumnsOfNodeTables)
             )
             .ToArray();
         foreach (var item in toRemove)
         {
             connectedSubGraph.IsTailNode[item.Value] = true;
         }
     }
 }
 /// <summary>
 /// If a table alias in the MATCH clause is defined in an upper-level context,
 /// to be able to translate this MATCH clause, this table alias must be re-materialized
 /// in the FROM clause of the current context and joined with the corresponding table
 /// in the upper-level context.
 /// </summary>
 /// <param name="query">Select query</param>
 /// <param name="nodes">A collection of node alias and match node instance</param>
 private void RematerilizeExtrenalNodeTableReference(WSelectQueryBlock query, Dictionary<string, MatchNode> nodes)
 {
     var tableRefs = query.FromClause.TableReferences;
     var tableSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
     var newTableRefs = new List<WTableReference>();
     for (int index = 0; index < tableRefs.Count; ++index)
     {
         var table = tableRefs[index] as WNamedTableReference;
         if (table == null)
         {
             newTableRefs.Add(tableRefs[index]);
             continue;
         }
         if (!nodes.ContainsKey(table.ExposedName.Value))
         {
             newTableRefs.Add(table);
         }
         else
         {
             tableSet.Add(table.ExposedName.Value);
         }
     }
     query.FromClause = new WFromClause
     {
         TableReferences = newTableRefs,
     };
     WBooleanExpression whereCondiction = null;
     foreach (var node in nodes.Where(node => !tableSet.Contains(node.Key)))
     {
         node.Value.External = true;
         var newWhereCondition = new WBooleanComparisonExpression
         {
             ComparisonType = BooleanComparisonType.Equals,
             FirstExpr = new WColumnReferenceExpression
             {
                 MultiPartIdentifier = new WMultiPartIdentifier(
                 new Identifier { Value = node.Key },
                 new Identifier { Value = "GlobalNodeId" })
             },
             SecondExpr = new WColumnReferenceExpression
             {
                 MultiPartIdentifier = new WMultiPartIdentifier(
                 new Identifier { Value = node.Value.RefAlias },
                 new Identifier { Value = "GlobalNodeId" })
             },
         };
         whereCondiction = WBooleanBinaryExpression.Conjunction(whereCondiction, newWhereCondition);
     }
     if (whereCondiction != null)
     {
         if (query.WhereClause == null)
         {
             query.WhereClause = new WWhereClause { SearchCondition = whereCondiction };
         }
         else
         {
             if (query.WhereClause.SearchCondition == null)
             {
                 query.WhereClause.SearchCondition = whereCondiction;
             }
             else
             {
                 query.WhereClause.SearchCondition = new WBooleanBinaryExpression
                 {
                     BooleanExpressionType = BooleanBinaryExpressionType.And,
                     FirstExpr = new WBooleanParenthesisExpression
                     {
                         Expression = query.WhereClause.SearchCondition
                     },
                     SecondExpr = new WBooleanParenthesisExpression
                     {
                         Expression = whereCondiction
                     }
                 };
             }
         }
     }
 }
        public override void Visit(WSelectQueryBlock node)
        {
            if (node.SelectElements == null || node.SelectElements.Count < 2)
            {
                throw new GraphViewException("Numbers of select elements mismatch.");
            }
            var sourceTableScalar = node.SelectElements[0] as WSelectScalarExpression;
            if (sourceTableScalar == null)
                throw new GraphViewException("Source node id should be a scalar expression.");
            var sourceTableColumn = sourceTableScalar.SelectExpr as WColumnReferenceExpression;
            if (sourceTableColumn == null)
                throw new GraphViewException("Source node id column should be a column reference expression.");
            var sourceTableName = sourceTableColumn.MultiPartIdentifier.Identifiers.Last().Value;

            var sourceNodeIdExpr = new WColumnReferenceExpression();
            foreach (var identifier in sourceTableColumn.MultiPartIdentifier.Identifiers)
                sourceNodeIdExpr.Add(identifier);
            sourceNodeIdExpr.AddIdentifier("GlobalNodeId");

            if (node.SelectElements.Count < 2)
                throw new GraphViewException("Source and Sink tables should be specified in select elements.");

            if (node.GroupByClause != null)
            {
                throw new GraphViewException("GROUP BY clause is not allowed in INSERT EDGE statement.");
            }
            var collectVarVisitor = new CollectVariableVisitor();
            var context = collectVarVisitor.Invoke(node);
            WColumnReferenceExpression sinkNodeIdExpr = null;

            for (var index = 1; index < node.SelectElements.Count; ++index)
            {
                var element = node.SelectElements[index] as WSelectScalarExpression;
                if (element == null)
                    throw new GraphViewException("Edge property should be a scalar expression.");
                //sink table
                if (index == 1)
                {
                    var sinkTableColumn = element.SelectExpr as WColumnReferenceExpression;
                    if (sinkTableColumn == null)
                        throw new GraphViewException("Sink node id column should be a column reference expression.");

                    var sinkTableName = sinkTableColumn.MultiPartIdentifier.Identifiers.Last().Value;
                    _sinkTable = context[sinkTableName];

                    sinkNodeIdExpr = new WColumnReferenceExpression();
                    foreach (var identifier in sinkTableColumn.MultiPartIdentifier.Identifiers)
                        sinkNodeIdExpr.Add(identifier);
                    sinkNodeIdExpr.AddIdentifier("GlobalNodeId");
                }
                else
                {
                    _edgeProperties.Add(element.SelectExpr);
                }

            }

            var sourceTable = context[sourceTableName] as WNamedTableReference;

            if (sourceTable == null)
            {
                throw new GraphViewException("Source table of INSERT EDGE statement should be a named table reference.");
            }


            var sourceNodeId = new WSelectScalarExpression
            {
                SelectExpr = sourceNodeIdExpr,
                ColumnName = "src",
            };
            var sinkNodeId = new WSelectScalarExpression
            {
                SelectExpr = sinkNodeIdExpr,
                ColumnName = "sink"
            };


            var elements = new List<WSelectElement>
            {
                sourceNodeId,
                sinkNodeId
            };

            var result = new WCommonTableExpression
            {
                ExpressionName = new Identifier {Value = _tempTableName},
                QueryExpression = new WSelectQueryBlock
                {
                    FromClause = node.FromClause,
                    WhereClause = new WWhereClause
                    {
                        SearchCondition = node.WhereClause.SearchCondition
                    },
                    HavingClause = node.HavingClause,
                    OrderByClause = node.OrderByClause,
                    TopRowFilter = node.TopRowFilter,
                    UniqueRowFilter = node.UniqueRowFilter,
                    SelectElements = elements,
                    MatchClause = node.MatchClause
                }
            };
            

            _result = result;
        }
        /// <summary>
        /// If paths is referenced in the MATCH clause, checks the SELECT elements to decide whether the 
        /// paths informaion is needed to be displayed. If PathAlias.* occurs in the SELECT elements,
        /// sets the corresponding bool value in MatchPath, and replaces this element with 
        /// an scalar function to display readable path information
        /// </summary>
        /// <param name="query">Select query</param>
        /// <param name="pathDictionary">A collection of path alias and match path instance</param>
        private void TransformPathInfoDisplaySelectElement(WSelectQueryBlock query,
            Dictionary<string, MatchPath> pathDictionary)
        {
            if (pathDictionary!=null && pathDictionary.Any())
            {
                List<WSelectElement> newSelectElements = new List<WSelectElement>();
                foreach (var selectElement in query.SelectElements)
                {
                    var starElement = selectElement as WSelectStarExpression;
                    if (starElement != null && starElement.Qulifier != null)
                    {
                        var colName = starElement.Qulifier.Identifiers[starElement.Qulifier.Count - 1].Value;
                        MatchPath path;
                        if (pathDictionary.TryGetValue(colName, out path))
                        {
                            path.ReferencePathInfo = true;
                            string schema = path.BindNodeTableObjName.SchemaIdentifier.Value;
                            string tableName = path.BindNodeTableObjName.BaseIdentifier.Value;
                            string pathName = path.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value;
                            var parameters = new List<WScalarExpression>
                            {
                                new WColumnReferenceExpression
                                {
                                    MultiPartIdentifier =
                                        new WMultiPartIdentifier(new Identifier() {Value = path.EdgeAlias},
                                            new Identifier() {Value = "PathMessage"})
                                },
                            };
                            if (
                                _graphMetaData.NodeViewMapping.ContainsKey(
                                    WNamedTableReference.SchemaNameToTuple(path.SinkNode.NodeTableObjectName)))
                            {
                                parameters.Add(new WColumnReferenceExpression
                                {
                                    MultiPartIdentifier =
                                        new WMultiPartIdentifier(new Identifier() { Value = path.SinkNode.RefAlias },
                                            new Identifier() { Value = "_NodeType" })
                                });
                                parameters.Add(new WColumnReferenceExpression
                                {
                                    MultiPartIdentifier =
                                        new WMultiPartIdentifier(new Identifier() { Value = path.SinkNode.RefAlias },
                                            new Identifier() { Value = "_NodeId" })
                                });
                            }
                            else
                            {
                                parameters.Add(new WValueExpression
                                {
                                    Value = path.SinkNode.NodeTableObjectName.BaseIdentifier.Value,
                                    SingleQuoted = true
                                });
                                string sinkNodeIdName =
                                    _graphMetaData.ColumnsOfNodeTables[
                                        WNamedTableReference.SchemaNameToTuple(path.SinkNode.NodeTableObjectName)]
                                        .FirstOrDefault(e => e.Value.Role == WNodeTableColumnRole.NodeId).Key;
                                if (string.IsNullOrEmpty(sinkNodeIdName))
                                    parameters.Add(new WValueExpression { Value = "null" });
                                else
                                {
                                    parameters.Add(new WColumnReferenceExpression
                                    {
                                        MultiPartIdentifier =
                                            new WMultiPartIdentifier(new Identifier() { Value = path.SinkNode.RefAlias },
                                                new Identifier() { Value = sinkNodeIdName })
                                    });
                                }

                            }
                            newSelectElements.Add(new WSelectScalarExpression
                            {
                                ColumnName = path.EdgeAlias + "_PathInfo",
                                SelectExpr = new WFunctionCall
                                {
                                    CallTarget = new WMultiPartIdentifierCallTarget
                                    {
                                        Identifiers = new WMultiPartIdentifier(new Identifier { Value = "dbo" })
                                    },
                                    FunctionName = new Identifier { Value = string.Format("{0}_{1}_{2}_PathMessageDecoder", schema, tableName, pathName) },
                                    Parameters = parameters
                                }
                            });
                            continue;
                        }
                    }
                    newSelectElements.Add(selectElement);

                }
                query.SelectElements = newSelectElements;
            }
        }
        /// <summary>
        /// The entry of the optimizer, activated when visting each Select Query Block
        /// </summary>
        /// <param name="node"></param>
        public override void Visit(WSelectQueryBlock node)
        {
            var checkVarVisitor = new CollectVariableVisitor();
            var currentContext = checkVarVisitor.Invoke(node.FromClause, _columnsOfNodeTables.Keys);
            currentContext.UpperLevel = _context;
            _context = currentContext;

            base.Visit(node);

            _statisticsCalculator.Context = _context;
            CheckValidity(node);
            var graph = ConstructGraph(node);
            //ChangeSelectStarExpression(node, graph);

            if (graph != null)
            {
                OptimizeTail(node, graph);
                EstimateRows(node, graph);
                EstimateAverageDegree(graph);

                var components = new List<MatchComponent>();
                foreach (var subGraph in graph.ConnectedSubGraphs)
                {
                    

                    components.Add(ConstructComponent(subGraph));
#if DEBUG
                    foreach (var matchNode in subGraph.Nodes.Values)
                    {
                        Trace.WriteLine(matchNode.NodeAlias);
                        Trace.WriteLine(string.Format("  RowCount:{0}", matchNode.TableRowCount));
                        Trace.WriteLine(string.Format("  EstiRow:{0}", matchNode.EstimatedRows));
                    }
#endif

                }

                UpdateQuery(node, components);

#if DEBUG
                Trace.WriteLine(string.Format("Rows:{0}", components[0].Size));
                Trace.WriteLine(string.Format("Cost:{0}", components[0].Cost));
                Trace.WriteLine(string.Format("Estimated Rows:{0}", components[0].EstimateSize));

#endif
                node.MatchClause = null;
            }

            _context = _context.UpperLevel;
        }
        /// <summary>
        /// Update FROM clause, adds DOWNSIZE predicates in the corresponding join conditions,
        /// and add corresponding predicates on the spilt nodes in the WHERE clause using 
        /// optimal component of each connected sub-graph.
        /// </summary>
        /// <param name="node">The SELECT statement</param>
        /// <param name="components">The optimal components of each fully-connected graph</param>
        private void UpdateQuery(WSelectQueryBlock node, List<MatchComponent> components)
        {
            // Removes schema name in SELECT clause and all column references.
            var removeSchemaVisitor = new RemoveSchemanameInIdentifersVisitor();
            removeSchemaVisitor.Visit(node);

            foreach (var component in components)
            {
                //// Cross apply the unmaterilized edges which point to the optimized tail nodes
                //Dictionary<MatchNode, MatchEdge> UnMatEdgeJoinDict = new Dictionary<MatchNode, MatchEdge>();
                //foreach (var unMatEdge in component.EdgeMaterilizedDict.Where(e => !e.Value).Select(e => e.Key))
                //{
                //    component.TableRef = component.SpanTableRef(component.TableRef,
                //        unMatEdge, component.GetNodeRefName(unMatEdge.SourceNode), _graphMetaData);
                //    MatchEdge joinEdge;
                //    if (UnMatEdgeJoinDict.TryGetValue(unMatEdge.SinkNode, out joinEdge))
                //    {
                //        if (!string.IsNullOrEmpty(newWhereString))
                //            newWhereString += " AND ";
                //        newWhereString += string.Format("{0}.Sink = {1}.Sink", joinEdge.EdgeAlias, unMatEdge.EdgeAlias);
                //    }
                //    else
                //    {
                //        UnMatEdgeJoinDict[unMatEdge.SinkNode] = unMatEdge;
                //    }
                //}

                // Updates from clause
                node.FromClause.TableReferences.Add(component.TableRef);
            }

            WBooleanExpression attachWhereCondition = null;
            foreach (var component in components)
            {
                attachWhereCondition = WBooleanBinaryExpression.Conjunction(attachWhereCondition,
                    component.WhereCondition);
            }

            if (attachWhereCondition != null)
            {
                if (node.WhereClause != null && node.WhereClause.SearchCondition != null)
                    node.WhereClause.SearchCondition = new WBooleanParenthesisExpression
                    {
                        Expression = node.WhereClause.SearchCondition
                    };
                else
                {
                    node.WhereClause = new WWhereClause();
                }
                node.WhereClause.SearchCondition = WBooleanBinaryExpression.Conjunction(attachWhereCondition,
                    node.WhereClause.SearchCondition);
            }
        }
 public override void Visit(WSelectQueryBlock node)
 {
     UpdateMapping(node);
 }
        /// <summary>
        /// The entry point of the optimizer, activated when visting each SELECT query block.
        /// </summary>
        /// <param name="node">The SELECT query block</param>
        public override void Visit(WSelectQueryBlock node)
        {
            var checkVarVisitor = new CollectVariableVisitor();
            var currentContext = checkVarVisitor.Invoke(node.FromClause, _graphMetaData.ColumnsOfNodeTables.Keys);
            currentContext.ParentContext = _context;
            _context = currentContext;

            base.Visit(node);

            CheckValidity(node);
            var graph = ConstructGraph(node);
            //ChangeSelectStarExpression(node, graph);

            if (graph != null)
            {
                //OptimizeTail(node, graph);
                AttachPredicates(node.WhereClause,graph);
                EstimateRows(graph);
                RetrieveStatistics(graph);

                var components = new List<MatchComponent>();
                foreach (var subGraph in graph.ConnectedSubGraphs)
                {

                    components.Add(ConstructComponent(subGraph, graph.ReversedEdgeDict, graph.SourceNodeStatisticsDict));
            #if DEBUG
                    foreach (var matchNode in subGraph.Nodes.Values)
                    {
                        Trace.WriteLine(matchNode.NodeAlias);
                        Trace.WriteLine(string.Format("  RowCount:{0}", matchNode.TableRowCount));
                        Trace.WriteLine(string.Format("  EstiRow:{0}", matchNode.EstimatedRows));
                    }
            #endif

                }

                UpdateQuery(node, components);

            #if DEBUG
                Trace.WriteLine(string.Format("Rows:{0}", components[0].Cardinality));
                Trace.WriteLine(string.Format("Cost:{0}", components[0].Cost));
                Trace.WriteLine(string.Format("Estimated Rows:{0}", components[0].SqlEstimatedSize));

            #endif
                node.MatchClause = null;
            }

            _context = _context.ParentContext;
        }
 public virtual void Visit(WSelectQueryBlock node)
 {
     node.AcceptChildren(this);
 }
Example #50
0
        private WSelectQueryExpression ParseSelectQueryStatement(QueryExpression queryExpr)
        {

            if (queryExpr == null)
            {
                return null;
            }

            switch (queryExpr.GetType().Name)
            {
                case "BinaryQueryExpression":
                    {
                        var bqe = queryExpr as BinaryQueryExpression;
                        var pQueryExpr = new WBinaryQueryExpression
                        {
                            All = bqe.All,
                            FirstQueryExpr = ParseSelectQueryStatement(bqe.FirstQueryExpression),
                            SecondQueryExpr = ParseSelectQueryStatement(bqe.SecondQueryExpression),
                            FirstTokenIndex = bqe.FirstTokenIndex,
                            LastTokenIndex = bqe.LastTokenIndex
                        };

                        //pQueryExpr.OrderByExpr = parseOrderbyExpr(bqe.OrderByClause);

                        return pQueryExpr;
                    }
                case "QueryParenthesisExpression":
                    {
                        var qpe = queryExpr as QueryParenthesisExpression;
                        var pQueryExpr = new WQueryParenthesisExpression
                        {
                            QueryExpr = ParseSelectQueryStatement(qpe.QueryExpression),
                            FirstTokenIndex = qpe.FirstTokenIndex,
                            LastTokenIndex = qpe.LastTokenIndex
                        };

                        //pQueryExpr.OrderByExpr = parseOrderbyExpr(qpe.OrderByClause);

                        return pQueryExpr;
                    }
                case "QuerySpecification":
                    {
                        var qs = queryExpr as QuerySpecification;
                        var pQueryExpr = new WSelectQueryBlock
                        {
                            FirstTokenIndex = qs.FirstTokenIndex,
                            LastTokenIndex = qs.LastTokenIndex,
                            SelectElements = new List<WSelectElement>(qs.SelectElements.Count),
                        };

                        //
                        // SELECT clause
                        // 
                        foreach (var wsel in qs.SelectElements.Select(ParseSelectElement).Where(wsel => wsel != null))
                        {
                            pQueryExpr.SelectElements.Add(wsel);
                        }

                        //
                        // Top row filter
                        // 
                        if (qs.TopRowFilter != null)
                        {
                            pQueryExpr.TopRowFilter = new WTopRowFilter
                            {
                                Percent = qs.TopRowFilter.Percent,
                                WithTies = qs.TopRowFilter.WithTies,
                                Expression = ParseScalarExpression(qs.TopRowFilter.Expression),
                                FirstTokenIndex = qs.TopRowFilter.FirstTokenIndex,
                                LastTokenIndex = qs.TopRowFilter.LastTokenIndex
                            };
                        }

                        pQueryExpr.UniqueRowFilter = qs.UniqueRowFilter;

                        //
                        // FROM clause
                        //
                        if (qs.FromClause != null && qs.FromClause.TableReferences != null)
                        {
                            pQueryExpr.FromClause.FirstTokenIndex = qs.FromClause.FirstTokenIndex;
                            pQueryExpr.FromClause.LastTokenIndex = qs.FromClause.LastTokenIndex;
                            pQueryExpr.FromClause.TableReferences = new List<WTableReference>(qs.FromClause.TableReferences.Count);
                            foreach (var pref in qs.FromClause.TableReferences.Select(ParseTableReference).Where(pref => pref != null))
                            {
                                pQueryExpr.FromClause.TableReferences.Add(pref);
                            }
                        }

                        //
                        // WHERE clause
                        //

                        if (qs.WhereClause != null && qs.WhereClause.SearchCondition != null)
                        {
                            pQueryExpr.WhereClause.FirstTokenIndex = qs.WhereClause.FirstTokenIndex;
                            pQueryExpr.WhereClause.LastTokenIndex = qs.WhereClause.LastTokenIndex;
                            pQueryExpr.WhereClause.SearchCondition = ParseBooleanExpression(qs.WhereClause.SearchCondition);
                        }

                        // GROUP-BY clause
                        if (qs.GroupByClause != null)
                        {
                            pQueryExpr.GroupByClause = ParseGroupbyClause(qs.GroupByClause);
                        }

                        // Having clause
                        if (qs.HavingClause != null)
                        {
                            pQueryExpr.HavingClause = new WHavingClause
                            {
                                SearchCondition = ParseBooleanExpression(qs.HavingClause.SearchCondition),
                                FirstTokenIndex = qs.HavingClause.FirstTokenIndex,
                                LastTokenIndex = qs.HavingClause.LastTokenIndex
                            };
                        }

                        //
                        // ORDER-BY clause
                        // 
                        if (qs.OrderByClause != null)
                        {
                            pQueryExpr.OrderByClause = ParseOrderbyClause(qs.OrderByClause);
                        }

                        return pQueryExpr;
                    }
                default:
                    return null;
            }
        }
        /// <summary>
        /// Update FROM clause, adds DOWNSIZE predicates in the corresponding join conditions,
        /// and add corresponding predicates on the spilt nodes in the WHERE clause using 
        /// optimal component of each connected sub-graph.
        /// </summary>
        /// <param name="node">The SELECT statement</param>
        /// <param name="components">The optimal components of each fully-connected graph</param>
        private void UpdateQuery(WSelectQueryBlock node, List<MatchComponent> components)
        {
            // Removes schema name in SELECT clause and all column references.
            var removeSchemaVisitor = new RemoveSchemanameInIdentifersVisitor();
            removeSchemaVisitor.Visit(node);

            string newWhereString = "";
            foreach (var component in components)
            {
                // Adds predicates for split nodes
                var component1 = component;
                foreach (
                    var compNode in
                        component.MaterializedNodeSplitCount.Where(
                            e => e.Value > 0 && e.Key.Predicates != null && e.Key.Predicates.Any()))
                {
                    var matchNode = compNode.Key;

                    WBooleanExpression newExpression =
                        matchNode.Predicates.Aggregate<WBooleanExpression, WBooleanExpression>(null,
                            WBooleanBinaryExpression.Conjunction);
                    string predicateString = newExpression.ToString();
                    var nodeCount = component1.MaterializedNodeSplitCount[matchNode];

                    while (nodeCount > 0)
                    {
                        newWhereString += " AND ";
                        string tempStr = predicateString.Replace(string.Format("[{0}]", matchNode.RefAlias.ToUpper()),
                            string.Format("[{0}_{1}]", matchNode.RefAlias.ToUpper(), nodeCount));
                        tempStr = tempStr.Replace(string.Format("[{0}]", matchNode.RefAlias.ToLower()),
                            string.Format("[{0}_{1}]", matchNode.RefAlias.ToLower(), nodeCount));
                        newWhereString += tempStr;
                        nodeCount--;
                    }
                }

                // Cross apply the unmaterilized edges which point to the optimized tail nodes
                Dictionary<MatchNode,MatchEdge> UnMatEdgeJoinDict = new Dictionary<MatchNode, MatchEdge>();
                foreach (var unMatEdge in component.EdgeMaterilizedDict.Where(e => !e.Value).Select(e=>e.Key))
                {
                    component.TableRef = component.SpanTableRef(component.TableRef,
                        unMatEdge, component.GetNodeRefName(unMatEdge.SourceNode),_graphMetaData);
                    MatchEdge joinEdge;
                    if (UnMatEdgeJoinDict.TryGetValue(unMatEdge.SinkNode, out joinEdge))
                    {
                        if (!string.IsNullOrEmpty(newWhereString))
                            newWhereString += " AND ";
                        newWhereString += string.Format("{0}.Sink = {1}.Sink", joinEdge.EdgeAlias, unMatEdge.EdgeAlias);
                    }
                    else
                    {
                        UnMatEdgeJoinDict[unMatEdge.SinkNode] = unMatEdge;
                    }
                }

                // Updates from clause
                node.FromClause.TableReferences.Add(component.TableRef);
            }

            if (!string.IsNullOrEmpty(newWhereString))
            {
                if (node.WhereClause!=null && node.WhereClause.SearchCondition!=null)
                    node.WhereClause.SearchCondition = new WBooleanParenthesisExpression
                    {
                        Expression = node.WhereClause.SearchCondition
                    };
                else
                {
                    node.WhereClause = new WWhereClause();
                }
                node.WhereClause.GhostString = newWhereString;
            }
            
        }
        /// <summary>
        /// Update from clause in the query using optimal component of each connected sub-graph
        /// </summary>
        /// <param name="node"></param>
        /// <param name="components"></param>
        private void UpdateQuery(WSelectQueryBlock node, List<MatchComponent> components)
        {
            string newWhereString = "";
            foreach (var component in components)
            {
                // Add down size predicates
                foreach (var joinTableTuple in component.FatherListofDownSizeTable)
                {
                    var joinTable = joinTableTuple.Item1;
                    joinTable.JoinCondition = WBooleanBinaryExpression.Conjunction(joinTable.JoinCondition,
                        new WBooleanComparisonExpression
                        {
                            ComparisonType = BooleanComparisonType.Equals,
                            FirstExpr = new WFunctionCall
                            {
                                CallTarget = new WMultiPartIdentifierCallTarget
                                {
                                    Identifiers = new WMultiPartIdentifier(new Identifier { Value = "dbo" })
                                },
                                FunctionName = new Identifier { Value = "DownSizeFunction" },
                                Parameters = new List<WScalarExpression>
                                {
                                    new WColumnReferenceExpression
                                    {
                                        MultiPartIdentifier = new WMultiPartIdentifier
                                        {
                                            Identifiers = new List<Identifier>
                                            {
                                                new Identifier{Value = joinTableTuple.Item2},
                                                new Identifier {Value = "LocalNodeid"}
                                            }
                                        }
                                    }
                                }
                            },
                            SecondExpr = new WValueExpression("1", false)
                        });
                }

                // Update from clause
                node.FromClause.TableReferences.Add(component.TableRef);
              
                // Add predicates for split nodes
                var component1 = component;
                foreach (
                    var compNode in
                        component.MaterializedNodeSplitCount.Where(
                            e => e.Value>0 && e.Key.Predicates != null && e.Key.Predicates.Any()))
                {
                    var matchNode = compNode.Key;

                    WBooleanExpression newExpression = null;
                    foreach (var predicate in matchNode.Predicates)
                    {
                        newExpression = WBooleanBinaryExpression.Conjunction(newExpression, predicate);
                    }
                    string predicateString = newExpression.ToString().ToLower();
                    var nodeCount = component1.MaterializedNodeSplitCount[matchNode];

                    while (nodeCount > 0)
                    {
                        newWhereString += " AND ";
                        newWhereString += predicateString.Replace(string.Format("[{0}]", matchNode.RefAlias.ToLower()),
                            string.Format("[{0}_{1}]", matchNode.RefAlias, nodeCount));
                        nodeCount--;
                    }
                }
            }
            if (newWhereString.Any())
            {
                node.WhereClause.SearchCondition = new WBooleanParenthesisExpression
                {
                    Expression = node.WhereClause.SearchCondition
                };
                node.WhereClause.GhostString = newWhereString;
            }

            var visitor2 = new DeleteSchemanameInSelectVisitor();
            visitor2.Invoke(node);
        }
Example #53
0
        internal bool HasAggregateFunctionInTheRepeatSelectQuery(WSelectQueryBlock repeatSelectQuery)
        {
            AggregateFunctionCountVisitor aggregateCountVisitor = new AggregateFunctionCountVisitor();

            return(aggregateCountVisitor.Invoke(repeatSelectQuery) > 0);
        }
        /// <summary>
        /// Constructs the graph pattern specified by the MATCH clause. 
        /// The graph pattern may consist of multiple fully-connected sub-graphs.
        /// </summary>
        /// <param name="query">The SELECT query block</param>
        /// <returns>A graph object contains all the connected componeents</returns>
        private MatchGraph ConstructGraph(WSelectQueryBlock query)
        {
            if (query == null || query.MatchClause == null)
                return null;

            var columnsOfNodeTables = _graphMetaData.ColumnsOfNodeTables;
            var nodeViewMapping = _graphMetaData.NodeViewMapping;
            var unionFind = new UnionFind();
            var edgeColumnToAliasesDict = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
            var pathDictionary = new Dictionary<string, MatchPath>(StringComparer.OrdinalIgnoreCase);
            var reversedEdgeDict = new Dictionary<string, MatchEdge>();
            var matchClause = query.MatchClause;
            var nodes = new Dictionary<string, MatchNode>(StringComparer.OrdinalIgnoreCase);
            var connectedSubGraphs = new List<ConnectedComponent>();
            var subGrpahMap = new Dictionary<string, ConnectedComponent>(StringComparer.OrdinalIgnoreCase);
            var parent = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            unionFind.Parent = parent;

            // Constructs the graph pattern specified by the path expressions in the MATCH clause
            foreach (var path in matchClause.Paths)
            {
                var index = 0;
                MatchEdge preEdge = null;
                for (var count = path.PathEdgeList.Count; index < count; ++index)
                {
                    var currentNodeTableRef = path.PathEdgeList[index].Item1;
                    var currentEdgeColumnRef = path.PathEdgeList[index].Item2;
                    var currentNodeExposedName = currentNodeTableRef.BaseIdentifier.Value;
                    var nextNodeTableRef = index != count - 1
                        ? path.PathEdgeList[index + 1].Item1
                        : path.Tail;
                    var nextNodeExposedName = nextNodeTableRef.BaseIdentifier.Value;
                    var patternNode = nodes.GetOrCreate(currentNodeExposedName);
                    if (patternNode.NodeAlias == null)
                    {
                        patternNode.NodeAlias = currentNodeExposedName;
                        patternNode.Neighbors = new List<MatchEdge>();
                        patternNode.External = false;
                        var nodeTable = _context[currentNodeExposedName] as WNamedTableReference;
                        if (nodeTable != null)
                        {
                            patternNode.NodeTableObjectName = nodeTable.TableObjectName;
                            if (patternNode.NodeTableObjectName.SchemaIdentifier == null)
                                patternNode.NodeTableObjectName.Identifiers.Insert(0, new Identifier {Value = "dbo"});
                        }
                    }

                    Identifier edgeIdentifier = currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last();
                    string schema = patternNode.NodeTableObjectName.SchemaIdentifier.Value.ToLower();
                    string nodeTableName = patternNode.NodeTableObjectName.BaseIdentifier.Value;
                    string bindTableName =
                        _context.EdgeNodeBinding[
                            new Tuple<string, string>(nodeTableName.ToLower(), edgeIdentifier.Value.ToLower())].ToLower();
                    var bindNodeTableObjName = new WSchemaObjectName(
                        new Identifier {Value = schema},
                        new Identifier {Value = bindTableName}
                        );
                    var edgeColumn =
                        columnsOfNodeTables[
                            WNamedTableReference.SchemaNameToTuple(bindNodeTableObjName)][
                                currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last().Value];
                    string edgeAlias = currentEdgeColumnRef.Alias;
                    //string revEdgeAlias = edgeAlias;
                    bool isReversed = path.IsReversed || edgeColumn.EdgeInfo.IsReversedEdge;
                    string currentRevEdgeName = null;

                    // get original edge name
                    var currentEdgeName = currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last().Value;
                    var originalSourceName = isReversed ?
                        (_context[nextNodeExposedName] as WNamedTableReference).TableObjectName.BaseIdentifier.Value
                        : (_context[currentNodeExposedName] as WNamedTableReference).TableObjectName.BaseIdentifier.Value;

                    if (isReversed)
                    {
                        var i = currentEdgeName.IndexOf(originalSourceName, StringComparison.OrdinalIgnoreCase) +
                            originalSourceName.Length;
                        currentRevEdgeName = currentEdgeName.Substring(i + 1,
                            currentEdgeName.Length - "Reversed".Length - i - 1);
                    }
                    else
                    {
                        var srcTuple = WNamedTableReference.SchemaNameToTuple(patternNode.NodeTableObjectName);
                        // [nodeView]-[edge]->[node/nodeView]
                        if (edgeColumn.Role == WNodeTableColumnRole.Edge && nodeViewMapping.ContainsKey(srcTuple))
                        {
                            var physicalNodeName =
                                _context.EdgeNodeBinding[new Tuple<string, string>(srcTuple.Item2, currentEdgeName.ToLower())];
                            currentRevEdgeName = physicalNodeName + "_" + currentEdgeName + "Reversed";
                        }
                        else
                        {
                            currentRevEdgeName = originalSourceName + "_" + currentEdgeName + "Reversed";
                        }
                    }

                    if (edgeAlias == null)
                    {
                        edgeAlias = !isReversed
                            ? string.Format("{0}_{1}_{2}", currentNodeExposedName, currentEdgeName, nextNodeExposedName)
                            : string.Format("{0}_{1}_{2}", nextNodeExposedName, currentRevEdgeName, currentNodeExposedName);

                        //when the current edge is a reversed edge, the key should still be the original edge name
                        //e.g.: TestDeleteEdgeWithTableAlias
                        var edgeNameKey = isReversed ? currentRevEdgeName : currentEdgeName;
                        if (edgeColumnToAliasesDict.ContainsKey(edgeNameKey))
                        {
                            edgeColumnToAliasesDict[edgeNameKey].Add(edgeAlias);
                        }
                        else
                        {
                            edgeColumnToAliasesDict.Add(edgeNameKey, new List<string> { edgeAlias });
                        }
                    }

                    MatchEdge edge, revEdge;
                    if (currentEdgeColumnRef.MinLength == 1 && currentEdgeColumnRef.MaxLength == 1)
                    {
                        var isEdgeView = edgeColumn.Role == WNodeTableColumnRole.EdgeView;
                        var hasRevEdge = edgeColumn.EdgeInfo.HasReversedEdge;
                        edge = new MatchEdge
                        {
                            IsEdgeView = isEdgeView,
                            IsReversedEdge = false,
                            HasReversedEdge = hasRevEdge,
                            SourceNode = patternNode,
                            EdgeColumn = currentEdgeColumnRef,
                            EdgeAlias = edgeAlias,
                            BindNodeTableObjName = bindNodeTableObjName,
                        };
                        _context.AddEdgeReference(edge);

                        if (hasRevEdge)
                        {
                            revEdge = new MatchEdge
                            {
                                IsEdgeView = isEdgeView,
                                IsReversedEdge = true,
                                SinkNode = patternNode,
                                EdgeColumn = new WEdgeColumnReferenceExpression()
                                {
                                    ColumnType = currentEdgeColumnRef.ColumnType,
                                    Alias = currentEdgeColumnRef.Alias,
                                    MaxLength = currentEdgeColumnRef.MaxLength,
                                    MinLength = currentEdgeColumnRef.MinLength,
                                    AttributeValueDict = currentEdgeColumnRef.AttributeValueDict,
                                    MultiPartIdentifier = new WMultiPartIdentifier(new Identifier()
                                    {
                                        QuoteType = currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last().QuoteType,
                                        Value = currentRevEdgeName,
                                    }),
                                },
                                EdgeAlias = edgeAlias,
                                //EdgeAlias = revEdgeAlias,
                            };
                            reversedEdgeDict[edge.EdgeAlias] = revEdge;
                        }
                    }
                    else
                    {
                        MatchPath matchPath = new MatchPath
                        {
                            SourceNode = patternNode,
                            EdgeColumn = currentEdgeColumnRef,
                            EdgeAlias = edgeAlias,
                            BindNodeTableObjName =
                                new WSchemaObjectName(
                                    new Identifier {Value = schema},
                                    new Identifier {Value = bindTableName}
                                    ),
                            MinLength = currentEdgeColumnRef.MinLength,
                            MaxLength = currentEdgeColumnRef.MaxLength,
                            ReferencePathInfo = false,
                            AttributeValueDict = currentEdgeColumnRef.AttributeValueDict
                        };
                        _context.AddEdgeReference(matchPath);
                        pathDictionary[edgeAlias] = matchPath;
                        edge = matchPath;
                    }

                    if (preEdge != null)
                    {
                        preEdge.SinkNode = patternNode;
                        if (preEdge.HasReversedEdge)
                        {
                            //var preSourceNode = preEdge.SourceNode;
                            var preEdgeBindNodeTableObjName = preEdge.BindNodeTableObjName;
                            var preEdgeColName = preEdge.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value;
                            var preEdgeColumn =
                                columnsOfNodeTables[
                                    WNamedTableReference.SchemaNameToTuple(preEdgeBindNodeTableObjName)][
                                        preEdgeColName];
                            var isEdgeView = preEdgeColumn.Role == WNodeTableColumnRole.EdgeView;
                            var isNodeView =
                                _graphMetaData.NodeViewMapping.ContainsKey(
                                    WNamedTableReference.SchemaNameToTuple(patternNode.NodeTableObjectName));

                            reversedEdgeDict[preEdge.EdgeAlias].SourceNode = patternNode;
                            // [node/nodeView]-[edgeView]->[node/nodeView]
                            if (isEdgeView)
                            {
                                reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = preEdgeBindNodeTableObjName;
                            }
                            // [node/nodeView]-[edge]->[nodeView]
                            else if (!isEdgeView && isNodeView)
                            {
                                reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = new WSchemaObjectName(
                                    new Identifier { Value = "dbo" },
                                    new Identifier { Value = preEdgeColumn.EdgeInfo.SinkNodes.First() }
                                    );
                            }
                            else
                            {
                                reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = new WSchemaObjectName(
                                    new Identifier { Value = schema },
                                    new Identifier { Value = bindTableName }
                                    );
                            }
                        }
                    }
                    preEdge = edge;

                    if (!parent.ContainsKey(currentNodeExposedName))
                        parent[currentNodeExposedName] = currentNodeExposedName;
                    if (!parent.ContainsKey(nextNodeExposedName))
                        parent[nextNodeExposedName] = nextNodeExposedName;

                    unionFind.Union(currentNodeExposedName, nextNodeExposedName);

                    patternNode.Neighbors.Add(edge);

                }
                var tailExposedName = path.Tail.BaseIdentifier.Value;
                var tailNode = nodes.GetOrCreate(tailExposedName);
                if (tailNode.NodeAlias == null)
                {
                    tailNode.NodeAlias = tailExposedName;
                    tailNode.Neighbors = new List<MatchEdge>();
                    var nodeTable = _context[tailExposedName] as WNamedTableReference;
                    if (nodeTable != null)
                    {
                        tailNode.NodeTableObjectName = nodeTable.TableObjectName;
                        if (tailNode.NodeTableObjectName.SchemaIdentifier == null)
                            tailNode.NodeTableObjectName.Identifiers.Insert(0, new Identifier {Value = "dbo"});
                    }
                }
                if (preEdge != null)
                {
                    preEdge.SinkNode = tailNode;
                    if (preEdge.HasReversedEdge)
                    {
                        var schema = tailNode.NodeTableObjectName.SchemaIdentifier.Value.ToLower();
                        var nodeTableName = tailNode.NodeTableObjectName.BaseIdentifier.Value;
                        //var preSourceNode = preEdge.SourceNode;
                        var preEdgeBindNodeTableObjName = preEdge.BindNodeTableObjName;
                        var preEdgeColName = preEdge.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value;
                        var preEdgeColumn =
                            columnsOfNodeTables[
                                WNamedTableReference.SchemaNameToTuple(preEdgeBindNodeTableObjName)][
                                    preEdgeColName];
                        var isEdgeView = preEdgeColumn.Role == WNodeTableColumnRole.EdgeView;
                        var isNodeView =
                            _graphMetaData.NodeViewMapping.ContainsKey(
                                WNamedTableReference.SchemaNameToTuple(tailNode.NodeTableObjectName));
                        reversedEdgeDict[preEdge.EdgeAlias].SourceNode = tailNode;
                        // [node/nodeView]-[edgeView]->[node/nodeView]
                        if (isEdgeView)
                        {
                            reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = preEdgeBindNodeTableObjName;
                        }
                        // [node/nodeView]-[edge]->[nodeView]
                        else if (!isEdgeView && isNodeView)
                        {
                            reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = new WSchemaObjectName(
                                new Identifier { Value = "dbo" },
                                new Identifier { Value = preEdgeColumn.EdgeInfo.SinkNodes.First() }
                                );
                        }
                        else
                        {
                            reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = new WSchemaObjectName(
                                new Identifier { Value = schema },
                                new Identifier { Value = nodeTableName.ToLower() }
                                );
                        }
                    }
                }
            }

            // Puts nodes into subgraphs
            foreach (var node in nodes)
            {
                string root = unionFind.Find(node.Key);
                if (!subGrpahMap.ContainsKey(root))
                {
                    var subGraph = new ConnectedComponent();
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGrpahMap[root] = subGraph;
                    connectedSubGraphs.Add(subGraph);
                    subGraph.IsTailNode[node.Value] = false;
                }
                else
                {
                    var subGraph = subGrpahMap[root];
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGraph.IsTailNode[node.Value] = false;
                }
            }

            var graph = new MatchGraph
            {
                ReversedEdgeDict = reversedEdgeDict,
                ConnectedSubGraphs = connectedSubGraphs,
                SourceNodeStatisticsDict = new Dictionary<Tuple<string, bool>, Statistics>(),
            };
            unionFind.Parent = null;

            // When an edge in the MATCH clause is not associated with an alias,
            // assigns to it a default alias: sourceAlias_EdgeColumnName_sinkAlias.
            // Also rewrites edge attributes anywhere in the query that can be bound to this default alias.
            var replaceTableRefVisitor = new ReplaceEdgeReferenceVisitor();
            replaceTableRefVisitor.Invoke(query, edgeColumnToAliasesDict);

            // Rematerializes node tables in the MATCH clause which are defined in the upper-level context
            // and join them with the upper-level table references.
            RematerilizeExtrenalNodeTableReference(query, nodes);

            // Transforms the path reference in the SELECT elements into a
            // scalar function to display path information.
            TransformPathInfoDisplaySelectElement(query, pathDictionary);

            return graph;
        }
        /// <summary>
        /// Replaces the SELECT * expression with all visible columns
        /// </summary>
        /// <param name="node"></param>
        /// <param name="graph"></param>
        private void ChangeSelectStarExpression(WSelectQueryBlock node, MatchGraph graph)
        {
            var newSelectElements = new List<WSelectElement>();
            Dictionary<string, List<WSelectElement>> starReplacement = null;
            foreach (var element in node.SelectElements)
            {
                var starElement = element as WSelectStarExpression;
                if (starElement != null)
                {
                    if (starReplacement == null)
                    {
                        starReplacement =
                            new Dictionary<string, List<WSelectElement>>(StringComparer.OrdinalIgnoreCase);
                        // Fetch table in order
                        foreach (var table in _context.NodeTableDictionary)
                        {
                            var alias = table.Key;
                            var namedTable = table.Value as WNamedTableReference;
                            if (namedTable != null)
                            {
                                foreach (
                                    var column in
                                        _graphMetaData.ColumnsOfNodeTables[
                                            WNamedTableReference.SchemaNameToTuple(namedTable.TableObjectName)].Where(
                                                e => e.Value.Role != WNodeTableColumnRole.Edge).Select(e => e.Key))
                                {
                                    var elementList = starReplacement.GetOrCreate(alias);
                                    elementList.Add(new WSelectScalarExpression
                                    {
                                        SelectExpr = new WColumnReferenceExpression
                                        {
                                            MultiPartIdentifier = new WMultiPartIdentifier
                                            {
                                                Identifiers = new List<Identifier>
                                                {
                                                    new Identifier {Value = alias},
                                                    new Identifier {Value = column}
                                                }
                                            }
                                        }

                                    });
                                }
                                if (graph == null) continue;
                                foreach (var subGraph in graph.ConnectedSubGraphs)
                                {
                                    if (subGraph.Nodes.ContainsKey(alias))
                                    {
                                        var matchNode = subGraph.Nodes[alias];
                                        foreach (var edge in matchNode.Neighbors)
                                        {
                                            var schemaName = edge.SourceNode.NodeTableObjectName.SchemaIdentifier ==
                                                             null
                                                ? "dbo"
                                                : edge.SourceNode.NodeTableObjectName.SchemaIdentifier.Value.ToLower();
                                            var nodeTuple = new Tuple<string, string>(schemaName,
                                                edge.SourceNode.NodeTableObjectName.BaseIdentifier.Value.ToLower());
                                            var edgeColumnName =
                                                edge.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value.ToLower();
                                            if (!_graphMetaData.ColumnsOfNodeTables[nodeTuple].ContainsKey(edgeColumnName))
                                            {
                                                throw new GraphViewException("Invalid Edge Alias");
                                            }
                                            foreach (
                                                var column in
                                                    _graphMetaData.ColumnsOfNodeTables[nodeTuple][edgeColumnName].EdgeInfo
                                                        .ColumnAttributes)
                                            {
                                                var elementList = starReplacement.GetOrCreate(edge.EdgeAlias);
                                                elementList.Add(new WSelectScalarExpression
                                                {
                                                    SelectExpr = new WColumnReferenceExpression
                                                    {
                                                        MultiPartIdentifier = new WMultiPartIdentifier
                                                        {
                                                            Identifiers = new List<Identifier>
                                                            {
                                                                new Identifier {Value = edge.EdgeAlias},
                                                                new Identifier {Value = column}
                                                            }
                                                        }
                                                    }

                                                });
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                var derivedTable = table.Value as WQueryDerivedTable;
                                if (derivedTable == null)
                                    continue;
                                var elementList = starReplacement.GetOrCreate(alias);
                                elementList.Add(new WSelectStarExpression
                                {
                                    Qulifier = new WMultiPartIdentifier
                                    {
                                        Identifiers = new List<Identifier> {new Identifier {Value = alias}}
                                    }
                                });

                            }
                        }
                    }
                    if (starElement.Qulifier != null)
                    {
                        newSelectElements.AddRange(starReplacement[starElement.Qulifier.Identifiers.Last().Value]);
                    }
                    else
                    {
                        foreach (var value in starReplacement.Values)
                        {
                            newSelectElements.AddRange(value);
                        }
                    }
                }
                else
                {
                    newSelectElements.Add(element);
                }
            }
            if (newSelectElements.Any())
                node.SelectElements = newSelectElements;
        }
        /// <summary>
        /// Construct Graph from the match clause. The Graph can consist of multiple connected SubGraph.
        /// Not supported in this version
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        private MatchGraph ConstructGraph(WSelectQueryBlock query)
        {
            var unionFind = new UnionFind();
            if (query.MatchClause == null)
                return null;
            var edgeTableReferenceDict = new Dictionary<string, List<string>>(StringComparer.CurrentCultureIgnoreCase);
            var matchClause = query.MatchClause;
            var nodes = new Dictionary<string, MatchNode>(StringComparer.CurrentCultureIgnoreCase);
            var connectedSubGraphs = new List<ConnectedComponent>();
            var subGrpahMap = new Dictionary<string, ConnectedComponent>(StringComparer.CurrentCultureIgnoreCase);
            var parent = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
            unionFind.Parent = parent;
            HashSet<Tuple<string, string>> nodeTypes = new HashSet<Tuple<string, string>>();

            //Construct Graph from Match Pattern
            foreach (var path in matchClause.Paths)
            {
                var index = 0;
                MatchEdge preEdge = null;
                for (var count = path.PathNodeList.Count; index < count; ++index)
                {
                    var currentNode = path.PathNodeList[index].Item1;
                    var currentEdge = path.PathNodeList[index].Item2;
                    var currentNodeExposedName = currentNode.BaseIdentifier.Value;
                    var nextNode = index != count - 1
                        ? path.PathNodeList[index + 1].Item1
                        : path.Tail;
                    var nextNodeExposedName = nextNode.BaseIdentifier.Value;
                    var node = nodes.GetOrCreate(currentNodeExposedName);
                    if (node.NodeAlias == null)
                    {
                        node.NodeAlias = currentNodeExposedName;
                        node.Neighbors = new List<MatchEdge>();
                        node.External = false;
                        var nodeTable = _context[currentNodeExposedName] as WNamedTableReference;
                        if (nodeTable != null)
                        {
                            node.TableObjectName = nodeTable.TableObjectName;
                            if (node.TableObjectName.SchemaIdentifier == null)
                                node.TableObjectName.Identifiers.Insert(0, new Identifier { Value = "dbo" });
                            var nodeTypeTuple = WNamedTableReference.SchemaNameToTuple(node.TableObjectName);
                            if (!nodeTypes.Contains(nodeTypeTuple))
                                nodeTypes.Add(nodeTypeTuple);

                        }
                    }

                    if (currentEdge.AliasRole == AliasType.Default)
                    {
                        var currentEdgeName = currentEdge.MultiPartIdentifier.Identifiers.Last().Value;
                        if (edgeTableReferenceDict.ContainsKey(currentEdgeName))
                        {
                            edgeTableReferenceDict[currentEdgeName].Add(currentEdge.Alias);
                        }
                        else
                        {
                            edgeTableReferenceDict.Add(currentEdgeName, new List<string> { currentEdge.Alias });
                        }
                    }
                    var edge = new MatchEdge
                    {
                        SourceNode = node,
                        EdgeColumn = new WColumnReferenceExpression
                        {
                            MultiPartIdentifier = new WMultiPartIdentifier
                            {
                                Identifiers = new List<Identifier>
                                {
                                    new Identifier {Value = node.NodeAlias},
                                    currentEdge.MultiPartIdentifier.Identifiers.Last()
                                }
                            }
                        },
                        EdgeAlias = currentEdge.Alias
                    };

                    if (preEdge != null)
                    {
                        preEdge.SinkNode = node;
                    }
                    preEdge = edge;

                    if (!parent.ContainsKey(currentNodeExposedName))
                        parent[currentNodeExposedName] = currentNodeExposedName;
                    if (!parent.ContainsKey(nextNodeExposedName))
                        parent[nextNodeExposedName] = nextNodeExposedName;

                    unionFind.Union(currentNodeExposedName, nextNodeExposedName);


                    node.Neighbors.Add(edge);


                    _context.AddEdgeReference(currentEdge.Alias, edge.SourceNode.TableObjectName, currentEdge);
                }
                var tailExposedName = path.Tail.BaseIdentifier.Value;
                var tailNode = nodes.GetOrCreate(tailExposedName);
                if (tailNode.NodeAlias == null)
                {
                    tailNode.NodeAlias = tailExposedName;
                    tailNode.Neighbors = new List<MatchEdge>();
                    var nodeTable = _context[tailExposedName] as WNamedTableReference;
                    if (nodeTable != null)
                    {
                        tailNode.TableObjectName = nodeTable.TableObjectName;
                        if (tailNode.TableObjectName.SchemaIdentifier == null)
                            tailNode.TableObjectName.Identifiers.Insert(0, new Identifier { Value = "dbo" });
                        var nodeTypeTuple = WNamedTableReference.SchemaNameToTuple(tailNode.TableObjectName);
                        if (!nodeTypes.Contains(nodeTypeTuple))
                            nodeTypes.Add(nodeTypeTuple);
                    }
                }
                if (preEdge != null) 
                    preEdge.SinkNode = tailNode;
            }

            // Put nodes into subgraphs
            foreach (var node in nodes)
            {
                string root = unionFind.Find(node.Key);
                if (!subGrpahMap.ContainsKey(root))
                {
                    var subGraph = new ConnectedComponent();
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGrpahMap[root] = subGraph;
                    connectedSubGraphs.Add(subGraph);
                    subGraph.IsTailNode[node.Value] = false;
                }
                else
                {
                    var subGraph = subGrpahMap[root];
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGraph.IsTailNode[node.Value] = false;
                }
            }

            // Replace Edge name alias with proper alias in the query
            var replaceTableRefVisitor = new ReplaceTableRefVisitor();
            replaceTableRefVisitor.Invoke(query, edgeTableReferenceDict);
            

            // If a table alias in the MATCH clause is defined in an upper-level context, 
            // to be able to translate this MATCH clause, this table alias must be re-materialized 
            // in the FROM clause of the current context and joined with the corresponding table
            // in the upper-level context. 
            var tableRefs = query.FromClause.TableReferences;
            var tableSet = new HashSet<string>(StringComparer.CurrentCultureIgnoreCase);
            var newTableRefs = new List<WTableReference>();
            for (int index = 0; index < tableRefs.Count; ++index)
            {
                var table = tableRefs[index] as WNamedTableReference;
                if (table == null)
                {
                    newTableRefs.Add(tableRefs[index]);
                    continue;
                }
                var tableTuple = WNamedTableReference.SchemaNameToTuple(table.TableObjectName);
                if (!nodeTypes.Contains(tableTuple))
                {
                    newTableRefs.Add(table);
                }
                else
                {
                    tableSet.Add(table.ExposedName.Value);
                }
            }
            query.FromClause = new WFromClause
            {
                TableReferences = newTableRefs,
            };
            WBooleanExpression whereCondiction = null;
            foreach (var node in nodes)
            {
                if (!tableSet.Contains(node.Key))
                {
                    node.Value.External = true;
                    var newWhereCondition = new WBooleanComparisonExpression
                    {
                        ComparisonType = BooleanComparisonType.Equals,
                        FirstExpr = new WColumnReferenceExpression
                        {
                            MultiPartIdentifier = new WMultiPartIdentifier(
                                new Identifier { Value = node.Key },
                                new Identifier { Value = "GlobalNodeId" })
                        },
                        SecondExpr = new WColumnReferenceExpression
                        {
                            MultiPartIdentifier = new WMultiPartIdentifier(
                                new Identifier { Value = node.Value.RefAlias },
                                new Identifier { Value = "GlobalNodeId" })
                        },
                    };
                    whereCondiction = WBooleanBinaryExpression.Conjunction(whereCondiction, newWhereCondition);
                }
            }
            if (whereCondiction != null)
            {
                if (query.WhereClause == null)
                {
                    query.WhereClause = new WWhereClause { SearchCondition = whereCondiction };
                }
                else
                {
                    if (query.WhereClause.SearchCondition == null)
                    {
                        query.WhereClause.SearchCondition = whereCondiction;
                    }
                    else
                    {
                        query.WhereClause.SearchCondition = new WBooleanBinaryExpression
                        {
                            BooleanExpressionType = BooleanBinaryExpressionType.And,
                            FirstExpr = new WBooleanParenthesisExpression
                            {
                                Expression = query.WhereClause.SearchCondition
                            },
                            SecondExpr = new WBooleanParenthesisExpression
                            {
                                Expression = whereCondiction
                            }
                        };
                    }
                }
            }

            var graph = new MatchGraph
            {
                ConnectedSubGraphs = connectedSubGraphs,
                NodeTypesSet = nodeTypes,
            };
            unionFind.Parent = null;
            return graph;
        }
        /// <summary>
        /// Checks the validity of the MATCH clause, including 
        /// (1) an edge is bound to a node table or node view, 
        /// (2) the source and the sink of an edeg in a path expression are bound to corresponding node tables, 
        ///     as specified when node tables are created, and 
        /// (3) The length constraint for a path construct is valid 
        /// </summary>
        /// <param name="node">True, if the MATCH clause passes the test; false, otherwise.</param>
        private void CheckValidity(WSelectQueryBlock node)
        {
            if (node.MatchClause == null)
                return;
            // Checks validity of the source node/node view
            if (node.MatchClause.Paths.All(
                path => path.PathEdgeList.All(
                    part => _context.CheckTable(part.Item1.BaseIdentifier.Value) &&
                            IsNodeTable(_context[part.Item1.BaseIdentifier.Value])
                    )
                ))
            {
                foreach (var path in node.MatchClause.Paths)
                {
                    var index = 0;
                    for (var count = path.PathEdgeList.Count; index < count; ++index)
                    {
                        var pathNode = path.PathEdgeList[index];
                        var table = _context[pathNode.Item1.BaseIdentifier.Value] as WNamedTableReference;
                        var edgeCol = pathNode.Item2;
                        var edge =
                            edgeCol.MultiPartIdentifier.Identifiers.Last().Value.ToLower();
                        var nodeTableTuple = WNamedTableReference.SchemaNameToTuple(table.TableObjectName);
                        var schema = nodeTableTuple.Item1;

                        // Binds edge/edge view to node/node view and check validity
                        string bindNode = _context.BindEdgeToNode(schema, edge, nodeTableTuple.Item2, _graphMetaData);
                        if (string.IsNullOrEmpty(bindNode))
                            throw new GraphViewException(string.Format("Edge/EdgeView {0} cannot be bind to {1}.{2}",
                                edge,
                                nodeTableTuple.Item1, nodeTableTuple.Item2));

                        // Check edge length
                        if (edgeCol.MinLength<0)
                            throw new GraphViewException(
                                string.Format(
                                    "The minimal length of the path {0} should be non-negative integer",
                                    edge));
                        if (edgeCol.MaxLength!=-1 && edgeCol.MinLength > edgeCol.MaxLength)
                            throw new GraphViewException(
                                string.Format(
                                    "The minimal length of the path {0} should not be larger than the maximal length",
                                    edge));

                        // Checks whether the sink of the edge/edge view exist
                        HashSet<string> edgeSinkNodes =
                            _graphMetaData.ColumnsOfNodeTables[new Tuple<string, string>(schema, bindNode)][edge].EdgeInfo
                                .SinkNodes;
                        HashSet<string> sinkNodes;
                        if (
                            !edgeSinkNodes.All(
                                e =>
                                    _graphMetaData.ColumnsOfNodeTables.ContainsKey(new Tuple<string, string>(
                                        schema.ToLower(), e))))
                            throw new GraphViewException(String.Format(CultureInfo.CurrentCulture,
                                "Node Table Referenced by the Edge {0} not exists", edge));

                        // Checks validity of sink node(s)
                        var nextNode = index != count - 1
                            ? path.PathEdgeList[index + 1].Item1
                            : path.Tail;
                        var getNextTable = _context[nextNode.BaseIdentifier.Value];
                        if (!IsNodeTable(getNextTable))
                            throw new GraphViewException("Node table expected in MATCH clause");

                        // Checks whether the intersection of the edge sink and sink node(s) is empty
                        var nextTable = getNextTable as WNamedTableReference;
                        if (nextTable == null ||
                            !_graphMetaData.NodeViewMapping.TryGetValue(
                                WNamedTableReference.SchemaNameToTuple(nextTable.TableObjectName), out sinkNodes))
                            sinkNodes = new HashSet<string> {nextTable.TableObjectName.BaseIdentifier.Value};
                        if (sinkNodes.All(e => !edgeSinkNodes.Contains(e)))
                        {
                            throw new GraphViewException(String.Format(CultureInfo.CurrentCulture,
                                "Wrong Reference Table {0}", nextTable.TableObjectName.BaseIdentifier.Value));
                        }
                    }
                }
            }
            else
            {
                throw new GraphViewException("Node table/view expected in MATCH clause");
            }
        }
Example #58
0
        public override void Visit(WSelectQueryBlock node)
        {
            base.Visit(node);
            var flag = false;

            for (var i = 0; i < MatchList.Count; ++i)
            {
                if (MatchFlag[i])
                {
                    continue;
                }

                var nextToken = node.LastTokenIndex + 1;
                while (nextToken < Tokens.Count && Tokens[nextToken].TokenType == TSqlTokenType.WhiteSpace)
                {
                    nextToken++;
                }

                var insideBlock = (node.FirstTokenIndex < MatchList[i].FirstTokenIndex &&
                                   (node.LastTokenIndex > MatchList[i].LastTokenIndex ||
                                    nextToken == MatchList[i].FirstTokenIndex));
                if (!insideBlock)
                {
                    continue;
                }

                nextToken = node.FromClause.LastTokenIndex + 1;
                while (nextToken < Tokens.Count && Tokens[nextToken].TokenType == TSqlTokenType.WhiteSpace)
                {
                    nextToken++;
                }
                // match clause should exactly follow FROM clause
                if (node.FromClause.TableReferences == null ||
                    nextToken != MatchList[i].FirstTokenIndex)
                {
                    var token = Tokens[nextToken];
                    _errors.Add(new ParseError(0, token.Offset, token.Line, token.Column,
                                               "MATCH clause should exactly follow FROM clause"));
                }

                // if a where/top row filter/group by/having clause exists, it should be followed by a match clause
                if (node.WhereClause.SearchCondition != null &&
                    node.WhereClause.FirstTokenIndex < MatchList[i].LastTokenIndex)
                {
                    var token = Tokens[nextToken];
                    _errors.Add(new ParseError(0, token.Offset, token.Line, token.Column,
                                               "WHERE clause should be followed by a MATCH clause"));
                }
                if (node.TopRowFilter != null &&
                    node.TopRowFilter.FirstTokenIndex < MatchList[i].LastTokenIndex)
                {
                    var token = Tokens[nextToken];
                    _errors.Add(new ParseError(0, token.Offset, token.Line, token.Column,
                                               "Top row filter should be followed by a MATCH clause"));
                }
                if (node.GroupByClause != null &&
                    node.GroupByClause.FirstTokenIndex < MatchList[i].LastTokenIndex)
                {
                    var token = Tokens[nextToken];
                    _errors.Add(new ParseError(0, token.Offset, token.Line, token.Column,
                                               "GROUP BY clause should be followed by a MATCH clause"));
                }
                if (node.HavingClause != null &&
                    node.HavingClause.FirstTokenIndex < MatchList[i].LastTokenIndex)
                {
                    var token = Tokens[nextToken];
                    _errors.Add(new ParseError(0, token.Offset, token.Line, token.Column,
                                               "HAVING clause should be followed by a MATCH clause"));
                }
                if (flag)
                {
                    var token = Tokens[nextToken];
                    _errors.Add(new ParseError(0, token.Offset, token.Line, token.Column,
                                               "Mutiple MATCH clauses in same query block"));
                }
                if (_errors.Count > 0)
                {
                    return;
                }
                if (node.LastTokenIndex < MatchList[i].FirstTokenIndex)
                {
                    node.LastTokenIndex = MatchList[i].LastTokenIndex;
                }

                flag = true;
                if (node.MatchClause != null && node.MatchClause.Paths != null && node.MatchClause.Paths.Any())
                {
                    foreach (var path in MatchList[i].Paths)
                    {
                        node.MatchClause.Paths.Add(path);
                    }
                }
                else
                {
                    node.MatchClause = MatchList[i];
                }
                MatchFlag[i] = true;
            }
        }