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; }
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, } }; }
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, } }, } }; }
/// <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; }
/// <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; }