使用 Firebird.NET 2.5 执行 SQL 脚本时出现问题(错误代码 = -104)

发布于 2024-09-10 08:39:15 字数 1486 浏览 14 评论 0原文

首先对不起我的英语。我有问题需要帮助。 我自己用c#制作了一个简单的工具。该工具可以连接到本地或远程 firebird 服务器(v.2.5)。我的工具可以在服务器上的某个位置创建指定的 .fdb 文件(数据库)。

我还有一个包含 SQL 语句(创建表、触发器等)的文件。我想在创建数据库后执行这个文件。执行此文件将填充用户数据库的结构 - 不是数据,只是结构。

但后来我尝试执行我的 SQL 脚本 - firebird 服务器返回一个

SQL 错误代码 = -104 令牌未知行 xxx 列 xxx。

这就是这个 CREATE TABLE SQL 语句中的一行,例如:

CREATE TABLE tb1
(
    col1 INTEGER NOT NULL,
    col2 VARCHAR(36)
); 

/* This next create statement causes an error */

CREATE TABLE tb2
(
    col1 INTEGER NOT NULL,
    col2 VARCHAR(36)
); 

如果我在文件中只留下一个 create 语句 - 一切都会好的...我不知道我是如何解释的(很清楚)或不)) - 换句话说 - 为什么我不能在一个事务中使用许多创建语句执行完整查询?我的主要方法是执行查询:

public static string Do(string conString, string query)
{
            using (FbConnection conn = new FbConnection())
            {
                try
                {
                    conn.ConnectionString = conString;
                    conn.Open();
                    FbTransaction trans = conn.BeginTransaction();
                    FbCommand cmd = new FbCommand(query, conn, trans);
                    cmd.ExecuteNonQuery();
                    trans.Commit();
                }
                catch (Exception ex)
                {
                    System.Windows.MessageBox.Show(ex.ToString());
                    return "Transaction Fail";
                }
            }
            return "Transaction Commited";
}

有一个查询是我的 SQL 文件。

Sorry for my English first of all. I have a problem and need help.
I have a simple tool made by myself on c#. This tool makes connect to local or remote firebird server (v.2.5). And my tool can create specified .fdb file (database) somewhere on the server.

Also I have a file with SQL statements (create table, triggers and so on). I want to execute this file after database was created. Executing this file will fill structure of user database - not data, only structure.

But then I try to execute my SQL script - firebird server returns a

SQL error code = -104 Token unknown line xxx column xxx.

That's the line on this CREATE TABLE SQL statement, for example:

CREATE TABLE tb1
(
    col1 INTEGER NOT NULL,
    col2 VARCHAR(36)
); 

/* This next create statement causes an error */

CREATE TABLE tb2
(
    col1 INTEGER NOT NULL,
    col2 VARCHAR(36)
); 

If I will leave only one create statement in my file - all will be good... I don't know how I explained (it's clear or not)) - another words - why can't I execute full query with many create statements in one transaction? There is my main method which executes query:

public static string Do(string conString, string query)
{
            using (FbConnection conn = new FbConnection())
            {
                try
                {
                    conn.ConnectionString = conString;
                    conn.Open();
                    FbTransaction trans = conn.BeginTransaction();
                    FbCommand cmd = new FbCommand(query, conn, trans);
                    cmd.ExecuteNonQuery();
                    trans.Commit();
                }
                catch (Exception ex)
                {
                    System.Windows.MessageBox.Show(ex.ToString());
                    return "Transaction Fail";
                }
            }
            return "Transaction Commited";
}

There is a query is my SQL file.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

ま昔日黯然 2024-09-17 08:39:15

正如 Victor 在他的最后评论中已经指出的那样,您可以使用 FBScript 类进行批量执行。

我刚刚面临同样的任务。这个问题为我指明了正确的方向,但我必须做一些进一步的挖掘。

在这个例子中,语句的来源是一个外部脚本文件:

private void ExecuteScript(FbConnection myConnection, string scriptPath) {
    if (!File.Exists(scriptPath))
        throw new FileNotFoundException("Script not found", scriptPath);

    FileInfo file = new FileInfo(scriptPath);
    string script = file.OpenText().ReadToEnd();

    // use FbScript to parse all statements
    FbScript fbs = new FbScript(script);
    fbs.Parse();

    // execute all statements
    FbBatchExecution fbe = new FbBatchExecution(myConnection, fbs);
    fbe.Execute(true);
}

这会很好地工作,但您可能想知道为什么这整个事情没有被事务包围。实际上,不支持将 FbBatchExecution 直接“绑定”到事务。

我尝试的第一件事是这个(不起作用

private void ExecuteScript(FbConnection myConnection, string scriptPath) {
    using (FbTransaction myTransaction = myConnection.BeginTransaction()) {
        if (!File.Exists(scriptPath))
            throw new FileNotFoundException("Script not found", scriptPath);

        FileInfo file = new FileInfo(scriptPath);
        string script = file.OpenText().ReadToEnd();

        // use FbScript to parse all statements
        FbScript fbs = new FbScript(script);
        fbs.Parse();

        // execute all statements
        FbBatchExecution fbe = new FbBatchExecution(myConnection, fbs);
        fbe.Execute(true);

        myTransaction.Commit();
    }
}

这将导致异常,指出:“当分配给命令的连接对象处于挂起状态时,执行要求命令对象有一个事务对象本地事务。命令的事务属性尚未初始化。”

这意味着 FbBatchExecution 执行的命令不会分配给代码块周围的本地事务。这里有帮助的是 FbBatchExecution 提供
在 CommandExecuting 事件中,我们可以拦截每个命令并像这样分配本地事务:

private void ExecuteScript(FbConnection myConnection, string scriptPath) {
    using (FbTransaction myTransaction = myConnection.BeginTransaction()) {
        if (!File.Exists(scriptPath))
            throw new FileNotFoundException("Script not found", scriptPath);

        FileInfo file = new FileInfo(scriptPath);
        string script = file.OpenText().ReadToEnd();

        // use FbScript to parse all statements
        FbScript fbs = new FbScript(script);
        fbs.Parse();

        // execute all statements
        FbBatchExecution fbe = new FbBatchExecution(myConnection, fbs);

        fbe.CommandExecuting += delegate(object sender, CommandExecutingEventArgs args) {
            args.SqlCommand.Transaction = myTransaction;
        };

        fbe.Execute(true);
        // myTransaction.Commit();
    }
}

请注意,我已取消注释 myTransaction.Commit() 行。我对这种行为感到有点惊讶,但如果保留该行,事务将抛出一个异常,表明它已经被提交。 bool 参数 fbe.Execute(true) 被命名为“autoCommit”,但将其更改为 false 似乎没有效果。

如果您发现以这种方式分配本地事务有任何潜在问题,或者它有任何好处或者也可以省略,我希望得到一些反馈。

As Victor already stated in his final comment, you can use the FBScript class for batch execution.

I was just confronted with the same task. This question pointed me in the right direction but i had to do some further digging.

I this example, the source of the statements is a external script file:

private void ExecuteScript(FbConnection myConnection, string scriptPath) {
    if (!File.Exists(scriptPath))
        throw new FileNotFoundException("Script not found", scriptPath);

    FileInfo file = new FileInfo(scriptPath);
    string script = file.OpenText().ReadToEnd();

    // use FbScript to parse all statements
    FbScript fbs = new FbScript(script);
    fbs.Parse();

    // execute all statements
    FbBatchExecution fbe = new FbBatchExecution(myConnection, fbs);
    fbe.Execute(true);
}

This will work fine, but you may wonder why this whole thing isn't surrounded by a transaction. Actually there is no support to "bind" FbBatchExecution to a transaction directly.

The first thing i tried was this (will not work)

private void ExecuteScript(FbConnection myConnection, string scriptPath) {
    using (FbTransaction myTransaction = myConnection.BeginTransaction()) {
        if (!File.Exists(scriptPath))
            throw new FileNotFoundException("Script not found", scriptPath);

        FileInfo file = new FileInfo(scriptPath);
        string script = file.OpenText().ReadToEnd();

        // use FbScript to parse all statements
        FbScript fbs = new FbScript(script);
        fbs.Parse();

        // execute all statements
        FbBatchExecution fbe = new FbBatchExecution(myConnection, fbs);
        fbe.Execute(true);

        myTransaction.Commit();
    }
}

This will result in an exception stating: "Execute requires the Command object to have a Transaction object when the Connection object assigned to the command is in a pending local transaction. The Transaction property of the Command has not been initialized."

This means nothing more than that the commands that are executed by FbBatchExecution are not assigned to our local transaction that is surrounding the code block. What helps here is that that FbBatchExecution provides
the event CommandExecuting where we can intercept every command and assign our local transaction like this:

private void ExecuteScript(FbConnection myConnection, string scriptPath) {
    using (FbTransaction myTransaction = myConnection.BeginTransaction()) {
        if (!File.Exists(scriptPath))
            throw new FileNotFoundException("Script not found", scriptPath);

        FileInfo file = new FileInfo(scriptPath);
        string script = file.OpenText().ReadToEnd();

        // use FbScript to parse all statements
        FbScript fbs = new FbScript(script);
        fbs.Parse();

        // execute all statements
        FbBatchExecution fbe = new FbBatchExecution(myConnection, fbs);

        fbe.CommandExecuting += delegate(object sender, CommandExecutingEventArgs args) {
            args.SqlCommand.Transaction = myTransaction;
        };

        fbe.Execute(true);
        // myTransaction.Commit();
    }
}

Note that i have uncommented the myTransaction.Commit() line. I was a little bit surprised by this behavior, but if you keep that line the transaction will throw an exception stating that it has already been committed. The bool parameter fbe.Execute(true) is named "autoCommit", but changing this to false seems to have no effect.

I would like some feedback if you see any potential issues with assigning the local transaction this way, or if it has any benefits at all or could as well be omitted.

牛↙奶布丁 2024-09-17 08:39:15

在一批中启动两个创建语句时可能会出错。如果将其分解为单独的查询,它会起作用吗?它在你的 SQL 工具中有效吗?

Probably error in launching two create statements in one batch. Would it work if you break it to separate queries? Does it work in your SQL tool?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文