SQL脚本数据中的关键字在以编程方式执行时导致问题 - C#

时间:2012-03-27 07:49:12

标签: c# sql sql-injection sqlcommand sql-insert

我是sql的新手,我的sql脚本中出现了严重问题。我正在尝试在C#中执行premade .sql脚本文件列表。我正在将文件读取为字符串并使用command.ExecuteNonQuery()执行它。这适用于大多数脚本,但我遇到了一个无意中包含关键字的脚本:

INSERT INTO [thetable]
SELECT '123123', 'abcabc', 'I WANT TO GO TO BED'
UNION ALL
SELECT '123124', 'abcdef', 'SOOO TIRED'

基本上,当它命中GO时命令失败。

我负责创建这些插入文件,所以如果我需要以某种方式重新格式化它们,那么这是可能的;但是,其中的数据是不可协商的。此外,由于我从一个包含许多行的文件中加载它们,因此参数化以避免这些内容似乎也不可行。

此时将非常感谢任何帮助。非常感谢!

编辑添加信息:

为了澄清,实际的字符串更像是'ASVFDS4 + 23eF3da34sddsdf3d3t4g ... 100charslater ... sd5OAyGOsiISIssdsd / sNUIGsdisd354f'。当我尝试执行命令时,我捕获了异常,其中说:

"Unclosed quotation mark after character string 'ASVFDS4+23eF3da34sddsdf3d3t4g...100charslater...sd5OAy'

请注意,GOOAIS紧跟着5OAy,这让我相信GO实际上被读作命令,导致它在该命令之前期望字符串结束。

运行.NET 3.5

编辑2 我还应该澄清,我目前正在拆分实际的GO语句并单独执行命令。

USE MyDatabase
GO
INSERT INTO [thetable]
SELECT '123123', 'abcabc', 'I WANT TO GO TO BED'
UNION ALL
SELECT '123124', 'abcdef', 'SOOO TIRED'
UNION ALL
...
SELECT '123189', 'abcabc', 'HAD SOME SLEEP'
GO

拆分,所以我执行

USE MyDatabase

INSERT INTO [thetable]
SELECT '123123', 'abcabc', 'I WANT TO GO TO BED'
UNION ALL
SELECT '123124', 'abcdef', 'SOOO TIRED'
UNION ALL
...
SELECT '123189', 'abcabc', 'HAD SOME SLEEP'

分开。所以我的问题不在于实际的GO语句,而是在数据字符串中出现字符“GO”。

ANSWER : 问题是我犯了一个非常愚蠢的错误。我拆分为“GO”,它将命令字符串分割在该参数的中间,其中出现字母GO。

/捂脸

感谢您的帮助!

2 个答案:

答案 0 :(得分:4)

如果你需要使用带有'go'(“smth go smth”)等的注释和字符串值来解析任何Sql脚本,你可以使用gplex工具。用于sql脚本解析的Gplex规则:

%namespace LexScanner
%option verbose, summary, noparser, unicode

%x QUOTE
%x COMMENT

%{
    static string line = "";
    static List<string> butch = new List<string>();
    enum TokenType {
        SL_COMMENT,
        ML_COMMENT,
        STRING,
        WORD,
        OTHER,
        ending
    };
%}

dotchr [^\r\n] 
eol (\r\n?|\n)
%%
\-\-[^\n]*$             { add(yytext, TokenType.SL_COMMENT); }

\/\*                    { add(yytext, TokenType.ML_COMMENT); BEGIN(COMMENT); }
<COMMENT>\*\/           { add(yytext, TokenType.ML_COMMENT); BEGIN(INITIAL); }
<COMMENT>[^\*]+         { add(yytext, TokenType.ML_COMMENT); }
<COMMENT>\*             { add(yytext, TokenType.ML_COMMENT); }

\'                      { add(yytext, TokenType.STRING); BEGIN(QUOTE); }
<QUOTE>\'\'             { add(yytext, TokenType.STRING); }
<QUOTE>[^\']+           { add(yytext, TokenType.STRING); }
<QUOTE>\'               { add(yytext, TokenType.STRING); BEGIN(INITIAL); }

[gG][oO]                { push(); }

[a-zA-Z0-9]+            { add(yytext, TokenType.WORD); }
.                       { add(yytext, TokenType.OTHER); }
\r?\n                   { add(yytext, TokenType.OTHER); }
<<EOF>>                 { push(); }
%%

然后生成C#类并使用它。

修改
更多评论如何使用它。
函数add(string text, TokenType token)push() - 如何处理解析后的字符串。 add()函数在GO关键字之间收集解析后的字符串,并将结果写入输出文件(仅用于控制):

private void add(string text, TokenType token)
{
    //write to the file for output control (for test only)
    using (StreamWriter str = new StreamWriter("C:\\temp\\temp.txt", true))
    {
        str.WriteLine(token + " : " + text); 
    }
    line += text;
}

push()收集butch字符串以供执行:

private void push()
{
    //write to the file for output control (for test only)
    using (StreamWriter str = new StreamWriter("C:\\temp\\butch.txt", true))
    {
        str.WriteLine("GO: " + line); 
    }

    butch.Add(line);
    line = "";
}

要从C#代码中使用此类,您应指定入口点。例如:

 public static List<string> ParseFile(String fileToParse)
 {
     int tok;
     Scanner scnr = new Scanner();
     scnr.SetSource(fileToParse, 0);
     do {
             tok = scnr.yylex();
         } while (tok > (int)Tokens.EOF);
     return butch;
 }

或者定义Main函数以将其用作独立应用程序。

以上所有代码都应放在.lex文件中。 通过从命令行调用来创建文件sqlparser.cs:

gplex sqlparser.lex

Gplex有一个很好的文档和示例如何使用它。

答案 1 :(得分:1)

您需要自己识别GO,并使用它将文件分批分批,然后逐个执行。

使用像m / ^ \ s + GO \ s + $ / i这样的正则表达式来识别GO行。