Example #1
0
        private static bool TryParseTokenList(TokenList <SqlToken> list, out SqlNode rootNode)
        {
            rootNode = null;

            Stack <SqlNode> stack = new Stack <SqlNode>();

            stack.Push(new SqlNode());

            TokenListParserResult <SqlToken, Token <SqlToken> > tmp;

            while ((tmp = list.ConsumeToken()).HasValue)
            {
                list = tmp.Remainder;

                if (tmp.Value.Kind == SqlToken.Comma)
                {
                    if (stack.Count < 1)
                    {
                        return(false);
                    }

                    stack.Pop();

                    SqlNode newNode = new SqlNode();
                    stack.Peek().AddChild(newNode);
                    stack.Push(newNode);

                    continue;
                }

                if (tmp.Value.Kind == SqlToken.ParenthesisStart)
                {
                    SqlNode newNode      = new SqlNode();
                    SqlNode newInnerNode = new SqlNode();
                    newNode.AddChild(newInnerNode);

                    stack.Peek().AddChild(newNode);
                    stack.Push(newNode);
                    stack.Push(newInnerNode);
                    continue;
                }

                if (tmp.Value.Kind == SqlToken.ParenthesisEnd)
                {
                    if (stack.Count < 2)
                    {
                        return(false);
                    }

                    stack.Pop();
                    stack.Pop();
                    continue;
                }

                stack.Peek().AddChild(new SqlNode(tmp.Value));
            }

            if (stack.Count != 1)
            {
                return(false);
            }

            rootNode = stack.Pop();
            return(true);
        }
Example #2
0
        /// <summary>
        /// Parses the tokens into structured table definition.
        /// </summary>
        /// <param name="definition">The textual definition of the <c>CREATE TABLE</c> statement.</param>
        /// <param name="tokens">A collection of tokens from the table definition.</param>
        /// <returns>Parsed data for a <c>CREATE TABLE</c> definition.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="tokens"/> is empty.</exception>
        public ParsedTableData ParseTokens(string definition, TokenList <SqliteToken> tokens)
        {
            if (definition.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(definition));
            }
            if (tokens == default || tokens.Empty())
            {
                throw new ArgumentNullException(nameof(tokens));
            }

            var next = tokens.ConsumeToken();
            var createTablePrefix = SqliteTokenParsers.CreateTablePrefix(next.Location);

            if (!createTablePrefix.HasValue)
            {
                throw new ArgumentException("Token list does not start with a CREATE TABLE statement.", nameof(tokens));
            }

            next = createTablePrefix.Remainder.ConsumeToken();
            var ifNotExists = SqliteTokenParsers.IfNotExistsClause(next.Location);

            if (ifNotExists.HasValue)
            {
                next = ifNotExists.Remainder.ConsumeToken();
            }

            var tableName = SqliteTokenParsers.QualifiedName(next.Location);

            if (!tableName.HasValue)
            {
                throw new ArgumentException("Unable to determine the name of the table being parsed.", nameof(tokens));
            }

            next = tableName.Remainder.ConsumeToken();
            var isSelectBasedTable = !next.HasValue || next.Value.Kind != SqliteToken.LParen;

            // skipping because we cannot parse extra information from a select-based table
            if (isSelectBasedTable)
            {
                return(ParsedTableData.Empty(definition));
            }

            next = next.Remainder.ConsumeToken(); // consume LParen

            var tableMembers = SqliteTokenParsers.TableMembers(next.Location);

            if (!tableMembers.HasValue)
            {
                var errMessage = "Unable to parse columns and/or constraints from the table definition. Error: " + tableMembers.ErrorMessage;
                throw new ArgumentException(errMessage, nameof(tokens));
            }

            var columns     = new List <Column>();
            var primaryKey  = Option <PrimaryKey> .None;
            var uniqueKeys  = new List <UniqueKey>();
            var foreignKeys = new List <ForeignKey>();
            var checks      = new List <Check>();

            var parsedColumns     = tableMembers.Value.SelectMany(m => m.Columns);
            var parsedConstraints = tableMembers.Value.SelectMany(m => m.Constraints);

            foreach (var parsedColumn in parsedColumns)
            {
                var column = new Column(
                    parsedColumn.Name,
                    parsedColumn.TypeDefinition,
                    parsedColumn.Nullable,
                    parsedColumn.IsAutoIncrement,
                    parsedColumn.Collation,
                    parsedColumn.DefaultValue,
                    parsedColumn.GeneratedColumnDefinition,
                    parsedColumn.GeneratedColumnType
                    );

                columns.Add(column);

                if (primaryKey.IsNone && parsedColumn.PrimaryKey.IsSome)
                {
                    primaryKey = parsedColumn.PrimaryKey;
                }

                parsedColumn.UniqueKey.IfSome(uk => uniqueKeys.Add(uk));
                foreignKeys.AddRange(parsedColumn.ForeignKeys);
                checks.AddRange(parsedColumn.Checks);
            }

            foreach (var parsedConstraint in parsedConstraints)
            {
                switch (parsedConstraint.ConstraintType)
                {
                case TableConstraint.TableConstraintType.PrimaryKey:
                    if (parsedConstraint is TableConstraint.PrimaryKey pk)
                    {
                        primaryKey = new PrimaryKey(pk.Name, pk.Columns);
                    }
                    break;

                case TableConstraint.TableConstraintType.UniqueKey:
                    if (parsedConstraint is TableConstraint.UniqueKey uk)
                    {
                        uniqueKeys.Add(new UniqueKey(uk.Name, uk.Columns));
                    }
                    break;

                case TableConstraint.TableConstraintType.ForeignKey:
                    if (parsedConstraint is TableConstraint.ForeignKey fk)
                    {
                        foreignKeys.Add(new ForeignKey(fk.Name, fk.Columns, fk.ParentTable, fk.ParentColumnNames));
                    }
                    break;

                case TableConstraint.TableConstraintType.Check:
                    if (parsedConstraint is TableConstraint.Check ck)
                    {
                        checks.Add(new Check(ck.Name, ck.Definition));
                    }
                    break;
                }
            }

            return(new ParsedTableData(
                       definition,
                       columns,
                       primaryKey,
                       uniqueKeys,
                       foreignKeys,
                       checks
                       ));
        }