示例#1
0
 private WColumnDefinition ParseColumnDefinition(ColumnDefinition columnDef)
 {
     if (columnDef == null)
         return null;
     var wColumnDef = new WColumnDefinition
     {
         FirstTokenIndex = columnDef.FirstTokenIndex,
         LastTokenIndex = columnDef.LastTokenIndex,
         ColumnIdentifier = columnDef.ColumnIdentifier,
         DataType = ParseDataType(columnDef.DataType),
         Collation = columnDef.Collation,
         ComputedColumnExpression = ParseScalarExpression(columnDef.ComputedColumnExpression),
         StorageOptions = columnDef.StorageOptions,
         Index = ParseIndexDefinition(columnDef.Index),
     };
     if (columnDef.Constraints != null)
     {
         wColumnDef.Constraints = new List<WConstraintDefinition>(columnDef.Constraints.Count);
         foreach (var con in columnDef.Constraints)
             wColumnDef.Constraints.Add(ParseConstraintDefinition(con));
     }
     if (columnDef.IdentityOptions != null)
         wColumnDef.IdentityOptions = new WIdentityOptions
         {
             FirstTokenIndex = columnDef.IdentityOptions.FirstTokenIndex,
             LastTokenIndex = columnDef.IdentityOptions.LastTokenIndex,
             IdentitySeed = ParseScalarExpression(columnDef.IdentityOptions.IdentitySeed),
             IdentityIncrement = ParseScalarExpression(columnDef.IdentityOptions.IdentityIncrement),
             IsIdentityNotForReplication = columnDef.IdentityOptions.IsIdentityNotForReplication,
         };
     return wColumnDef;
 }
示例#2
0
        /// <summary>
        /// Parses a CREATE TABLE statement. The parser first replaces column annotations with white space, 
        /// then uses T-SQL parser to parse it, and finally interprets the column annotations.
        /// </summary>
        /// <param name="queryStr">The CREATE TABLE statement creating a ndoe table</param>
        /// <param name="nodeTableColumns">A list of columns of the node table</param>
        /// <param name="errors">Parsing errors</param>
        /// <returns>The syntax tree of the CREATE TABLE statement</returns>
        public WSqlFragment ParseCreateNodeTableStatement(
            string queryStr, 
            out List<WNodeTableColumn> nodeTableColumns, 
            out IList<ParseError> errors)
        {
            // Gets token stream
            var tsqlParser = new TSql110Parser(true);
            var sr = new StringReader(queryStr);
            var tokens = new List<TSqlParserToken>(tsqlParser.GetTokenStream(sr, out errors));
            if (errors.Count > 0)
            {
                nodeTableColumns = null;
                return null;
            }

            // Retrieves node table columns
            var currentToken = 0;
            var farestError = 0;
            nodeTableColumns = new List<WNodeTableColumn>();
            while (currentToken < tokens.Count)
            {
                WNodeTableColumn column = null;
                if (ParseNodeTableColumn(tokens, ref currentToken, ref column, ref farestError))
                    nodeTableColumns.Add(column);
                else
                    currentToken++;
            }

            // Replaces column annotations with whitespace
            foreach (var t in nodeTableColumns)
            {
                tokens[t.FirstTokenIndex].TokenType = TSqlTokenType.WhiteSpace;
                tokens[t.FirstTokenIndex].Text = "";
            }

            // Parses the remaining statement using the T-SQL parser
            //IList<ParseError> errors;
            var parser = new WSqlParser();
            var fragment = parser.Parse(tokens, out errors) as WSqlScript;
            if (errors.Count > 0)
                return null;

            // In addition to columns specified in the CREATE TABLE statement,
            // adds an additional column recording the incoming degree of nodes.
            var inDegreeCol = new WColumnDefinition
            {
                ColumnIdentifier = new Identifier { Value = "InDegree" },
                Constraints = new List<WConstraintDefinition>{new WNullableConstraintDefinition { Nullable = false }},
                DataType = new WParameterizedDataTypeReference
                {
                    Name = new WSchemaObjectName(new Identifier { Value = "int" }),
                },
                DefaultConstraint = new WDefaultConstraintDefinition
                {
                    Expression = new WValueExpression
                    {
                        Value = "0"
                    }
                }
            };

            var deltaColumnDefList = new List<WColumnDefinition>();

            
            WCreateTableStatement stmt = fragment.Batches[0].Statements[0] as WCreateTableStatement;
            if (stmt == null || stmt.Definition == null || stmt.Definition.ColumnDefinitions==null)
            {
                return null;
            }
            else if (stmt.Definition.ColumnDefinitions.Count != nodeTableColumns.Count)
            {
                var error = tokens[stmt.FirstTokenIndex];
                errors.Add(new ParseError(0, error.Offset, error.Line, error.Column,
                    "Metadata should be specified for each column when creating a node table"));
            }
            

            var graphColIndex = 0;
            var rawColumnDef = stmt.Definition.ColumnDefinitions;
            for (var i = 0; i < rawColumnDef.Count && graphColIndex < nodeTableColumns.Count; ++i, ++graphColIndex)
            {
                var nextGraphColumn = nodeTableColumns[graphColIndex];
                // Skips columns without annotations
                while (i < rawColumnDef.Count && rawColumnDef[i].LastTokenIndex < nextGraphColumn.FirstTokenIndex)
                {
                    ++i;
                }

                switch (nextGraphColumn.ColumnRole)
                {
                    case WNodeTableColumnRole.Edge:
                        // For an adjacency-list column, its data type is always varbinary(max)
                        var def = rawColumnDef[i];
                        def.DataType = new WParameterizedDataTypeReference
                        {
                            Name = new WSchemaObjectName(new Identifier { Value = "varbinary" }),
                            Parameters = new List<Literal> { new MaxLiteral { Value = "max" } }
                        };
                        def.Constraints.Add(new WNullableConstraintDefinition { Nullable = false });
                        def.DefaultConstraint = new WDefaultConstraintDefinition
                        {
                            Expression = new WValueExpression
                            {
                                Value = "0x"
                            }
                        };
                        // For each adjacency-list column, adds a "delta" column to 
                        // facilitate deleting edges.
                        deltaColumnDefList.Add(new WColumnDefinition
                        {
                            ColumnIdentifier = new Identifier { Value = def.ColumnIdentifier.Value + "DeleteCol" },
                            ComputedColumnExpression = def.ComputedColumnExpression,
                            Constraints = def.Constraints,
                            DataType = def.DataType,
                            DefaultConstraint = def.DefaultConstraint,
                        });
                        // For each adjacency-list column, adds an integer column to record the list's outgoing degree
                        deltaColumnDefList.Add(new WColumnDefinition
                        {
                            ColumnIdentifier = new Identifier { Value = def.ColumnIdentifier.Value + "OutDegree" },
                            Constraints = def.Constraints,
                            DataType = new WParameterizedDataTypeReference
                            {
                                Name = new WSchemaObjectName(new Identifier { Value = "int" }),
                            },
                            DefaultConstraint = new WDefaultConstraintDefinition
                            {
                                Expression = new WValueExpression
                                {
                                    Value = "0"
                                }
                            }


                        });
                        break;
                    case WNodeTableColumnRole.NodeId:
                        // set unique key to user defined node id
                        bool containNullableConstraint = false;
                        foreach (var con in rawColumnDef[i].Constraints)
                        {
                            var nullableConstraint = con as WNullableConstraintDefinition;
                            if (nullableConstraint != null)
                            {
                                containNullableConstraint = true;
                                nullableConstraint.Nullable = false;
                                break;
                            }
                        }
                        if (!containNullableConstraint)
                        {
                            rawColumnDef[i].Constraints.Add(new WNullableConstraintDefinition { Nullable = false });
                        }
                        rawColumnDef[i].Constraints.Add(new WUniqueConstraintDefinition
                        {
                            Clustered = false,
                            IsPrimaryKey = false,
                        });
                        break;
                }
            }

            // Adds a GlobalNodeID column to the node table.
            // This column is the primary key of the node table. 
            var globalNodeIdCol = new WColumnDefinition
            {
                ColumnIdentifier = new Identifier { Value = "GlobalNodeId" },
                DataType = new WParameterizedDataTypeReference
                {
                    Name = new WSchemaObjectName(new Identifier { Value = "bigint" }),
                },
                Constraints = new List<WConstraintDefinition>
                    {
                        new WUniqueConstraintDefinition
                        {
                            Clustered = true,
                            IsPrimaryKey = true,
                            ConstraintIdentifier =
                                new Identifier
                                {
                                    Value =
                                        (stmt.SchemaObjectName.SchemaIdentifier == null
                                            ? "dbo"
                                            : stmt.SchemaObjectName.SchemaIdentifier.Value) +
                                        stmt.SchemaObjectName.BaseIdentifier.Value + "_PK_GlobalNodeId"
                                }
                        }
                    },
                IdentityOptions = new WIdentityOptions
                {
                    IdentitySeed = new WValueExpression("1", false),
                    IdentityIncrement = new WValueExpression("1", false),
                },
            };

            // Adds an identity column to the node table. 
            // This column will be used to adjust size estimation. 
            var identityCol = new WColumnDefinition
            {
                ColumnIdentifier = new Identifier { Value = "LocalNodeId" },
                DataType = new WParameterizedDataTypeReference
                {
                    Name = new WSchemaObjectName(new Identifier { Value = "int" }),
                },
                DefaultConstraint = new WDefaultConstraintDefinition
                {
                    Expression = new WFunctionCall
                    {
                        FunctionName = new Identifier { Value = "CHECKSUM" },
                        Parameters = new List<WScalarExpression>
                            {
                                new WFunctionCall
                                {
                                    FunctionName = new Identifier{Value = "NEWID"},
                                    Parameters = new List<WScalarExpression>()
                                }
                            }
                    }
                }

            };

            
            foreach (var definition in deltaColumnDefList)
            {
                stmt.Definition.ColumnDefinitions.Add(definition);
            }
            stmt.Definition.ColumnDefinitions.Add(globalNodeIdCol);
            stmt.Definition.ColumnDefinitions.Add(identityCol);
            stmt.Definition.ColumnDefinitions.Add(inDegreeCol);

            return fragment;
        }