尝试为SQL IN运算符编写语法和树解析器

时间:2015-07-08 18:12:29

标签: c# sql antlr3

我是ANTLR的新手,目前正在阅读“最终的ANTLR参考”。

我能够使用ANTLR找到一个可以解析一些基本SQL语句的现有程序。但是,我需要扩展此程序,以便我可以解析IN运算符在WHERE子句中的语句。

我能够得到一些半工作的东西(我正在使用ANTLR版本3)。

Combinations of IN Operator
-- IN (21) -- Works correct, even for (21, 86, 155)
-- IN (50-100) -- Works correct even for multiple ranges ( (50-100, 120-200, 350-420))
-- IN (21, 50-100)
-- IN (50-100, 21, 150-200)
-- IN (21, 50-100, 155)
-- IN (21, 86, 50-100, 155)

我的代码在所有其他场景中都不起作用 - 我必须遗漏一些东西。

这是我在语法文件中写的:

.........
.......
// in expression
inExpression
    :   field_name RESERVED_NOT? RESERVED_IN^ inCondition   
    ;

inCondition
    :   OPEN_PAREN! 
        ( (select_statement) => select_statement
        | (inElement) (COMMA! inElement)*)
        CLOSE_PAREN!
    ;

inElement
    : unary_expression
    | range_expression
    ;

...........
............
unary_expression
    : constant
    ;

// MCK
range_expression
    : unary_expression RANGE^ unary_expression
    ;

constant 
    : INT 
    | FLOAT 
    | STRING 
    | CHAR
    ;

这是我的树解析器。我无法弄清楚需要采取哪些措施来支持上面提到的IN运算符的所有方案:

joinCondition returns [SqlWhere cond = null;]
    @init {
        List<string> inList = new List<string>();
        bool notModifier = false;
        StringBuilder builder = new StringBuilder(255);
        List<string> rangeList = new List<string>();    
    }
: ^(RESERVED_IN field = fieldName (RESERVED_NOT { notModifier = true; })? ((node1 = unaryExpression 
        {       
            inList.Add(node1.Text);
        }
    )* 
    |
    (rlist = rangeExpression
        {
            foreach(CommonTree ritem in rlist)
            {
                rangeList.Add(ritem.Text);
            }
        }
    )* ) )
{
    if(inList.Count > 0)
    {
        int i = 0;

        if (!field.IsComplex)
        {
            field.Parameters = parameters;

            // Append the field name into the buffer
            //builder.Append("(");
            builder.Append(field.ToString());

            // If the not modifier is being used
            if (notModifier)
            {
                builder.Append(" NOT ");
            }

            // Place the paren
            builder.Append(" IN (");

            // Build the in list
            foreach (string inItem in inList)
            {
                if (i == 0)
                {
                    builder.Append(inItem);
                }
                else
                {
                    builder.Append(", ");
                    builder.Append(inItem);
                }
                i++;
            }

            builder.Append(')');

            if (field.Type == ColumnType.ForeignKey)
            {
                Query.AddSubQueryWhere(new SqlWhere(builder.ToString()));
            }
            else
            {
                $cond = new SqlWhere(builder.ToString());
            }
        }
    }               
    if (rangeList.Count > 0)
    {
        int i = 0;
        // build the rangeList with BETWEEN and AND
        foreach(string rangeItem in rangeList)
        {
            if (i == 0 || ((i \% 2) == 0))
            {
                if(inList.Count > 0 || i > 1)
                {
                    builder.Append(" OR ");
                }
                builder.Append("(");
                builder.Append(field.ToString());
                builder.Append(" BETWEEN ");
                builder.Append(rangeItem);
                builder.Append(" AND ");
            }
            else
            {
                builder.Append(rangeItem);
                builder.Append(") ");
            }                           
            i++;            
        }
        if (field.Type == ColumnType.ForeignKey)
        {
            Query.AddSubQueryWhere(new SqlWhere(builder.ToString()));
        }
        else
        {
            $cond = new SqlWhere(builder.ToString());
        }
    }       
}

........ ......

unaryExpression returns [string cons]
    : #(UNARY_MINUS conString = constant)
    {
        $cons = String.Format("-{0}", conString);
    }
    | #(UNARY_PLUS conString = constant)
    {
        $cons = conString;
    }
    | conString = constant
    {
        $cons = conString;
    }
    ;

 // MCK
rangeExpression returns [List<string> row]
@init
    {
        $row = new List<string>();
    }
    : ^(RANGE left=unaryExpression right=unaryExpression)
    {
        $row.Add(left);
        $row.Add(right);
    }
    ;


constant returns [string cons]
    : ni=INT 
    {
        $cons = ni.Text;
    }
    | nf=FLOAT 
    {
        $cons = nf.Text;
    }
    | sl=STRING 
    {
        $cons = "\"" + sl.Text + "\"";
    }
    | cl=CHAR
    {
        $cons = cl.Text;
    }
    ;

0 个答案:

没有答案