【问题标题】:Is it possible to write large strings to Firebird blob?是否可以将大字符串写入 Firebird blob?
【发布时间】:2021-10-06 23:10:51
【问题描述】:

Firebird 的文档暗示您可以将大 (> 60K) 字符串写入表中的 blob 值。所以如果你有这个:

CREATE TABLE MyBlobTable (
theId int PRIMARY KEY NOT NULL,
theBlob BLOB SUB_TYPE 1
)

那么这应该可以工作:

insert into MyBlobTable (theId, theBlob) values (1, '[60K characters in a string]')

(受http://web.firebirdsql.org/dotnetfirebird/blob-sub_type-1-reading-example-csharp.html启发的示例)

但我发现 C# 驱动程序和 FlameRobin 都不能写入这个值。你得到'Unexpected end of command'(指向字符串中大约 32K 的点,这有点可疑)

我认为有一种特殊的方法可以引用或转义数据值,或者可能是此 Java 代码 (http://www.firebirdfaq.org/faq372/) 的 C# 等效项,其中将二进制文件直接读入陈述。我没有对文本数据做任何花哨的事情,因此如果需要,我愿意将其存储为二进制 blob。

谢谢!

更新:“参数化查询”是我正在寻找的短语。我在做什么:

FbParameter param = new FbParameter("@blobVal", FbDbType.Text);
param.Value = myLargeString;
String query = "insert into MyBlobTable (theId, theBlob) values (1, @blobVal)";
using (FbConnection conn = [something from my pool]) {
    using (FbCommand cmd = new FbCommand(query, conn)) {
        cmd.Parameters.Add(param);
        cmd.ExecuteNonQuery();
    }
}

【问题讨论】:

  • 你能提醒我们什么是 SUBTYPE 1 吗?无论如何,尝试使用参数。
  • BLOB SUB_TYPE 1 映射到 C# 中的字符串,而 BLOB 映射到字节数组。

标签: c# blob firebird


【解决方案1】:

您在查询中添加内联文本。然后有限制:Firebird 2.5 和更早版本中的第一个查询文本限制为 64 KB,在 Firebird 3.0 中增加到 10 MB,但某些工具可能仍以将其限制为 64 KB 的方式使用 API。字符串文字大小也有一个限制:32KB,如果是 blob 值的文字,则自 Firebird 3.0 起为 64KB。

如果要向 blob 添加更多数据,则需要使用参数化查询将其流式传输到 blob。见this example

public static void Main(string[] args) {
    // Set the ServerType to 1 for connect to the embedded server
    string connectionString =
        "User=SYSDBA;" +
        "Password=masterkey;" +
        "Database=SampleDatabase.fdb;" +
        "DataSource=localhost;" +
        "Port=3050;" +
        "Dialect=3;" +
        "Charset=NONE;" +
        "Role=;" +
        "Connection lifetime=15;" +
        "Pooling=true;" +
        "Packet Size=8192;" +
        "ServerType=0";
    
    FbConnection myConnection = new FbConnection(connectionString);
    myConnection.Open();
    
    FbTransaction myTransaction = myConnection.BeginTransaction();
    
    FbCommand myCommand = new FbCommand();
    
    myCommand.CommandText =
        "UPDATE TEST_TABLE_01 SET CLOB_FIELD = @CLOB_FIELD WHERE INT_FIELD = @INT_FIELD";
    myCommand.Connection = myConnection;
    myCommand.Transaction = myTransaction;
    
    myCommand.Parameters.Add("@INT_FIELD", FbType.Integer, "INT_FIELD");
    myCommand.Parameters.Add("@CLOB_FIELD", FbType.Text, "CLOB_FIELD");
    
    myCommand.Parameters[0].Value = 1;
    myCommand.Parameters[1].Value = GetFileContents(@"GDS.CS");
    
    // Execute Update
    myCommand.ExecuteNonQuery();
    
    // Commit changes
    myTransaction.Commit();
    
    // Free command resources in Firebird Server
    myCommand.Dispose();
    
    // Close connection
    myConnection.Close(); 
}

public static string GetFileContents(string fileName) {
    StreamReader reader = new StreamReader(new FileStream(fileName, FileMode.Open));
    string contents = reader.ReadToEnd();
    reader.Close();
    return contents; 
}

【讨论】:

  • 很遗憾,这个例子已经找不到了,你能查一下吗?
  • @anli 我找不到替代品,所以我链接到 Wayback Machine,并引用了那里的示例
【解决方案2】:

我认为您达到了max length of varchar(n) type 的限制 - 32767 字节。尽管目标字段是 BLOB,但 API 会将值视为 varchar,因为您将其作为字符串文字提供。所以解决方案应该是使用参数化查询(对不起,我自己不使用C#,因此无法提供示例)。

【讨论】:

    【解决方案3】:

    可能这个大字符串对于 SQL 语句来说太多了。我还阅读了here,Firebird 中的 blob 无法通过 SQL 访问以进行写入(但我不确定此信息是否正确)。

    无论如何,您可以使用流来写入/读取 blob。例如,来自 SO:c# - reading/writing blob from firebird,使用字节数组进行存储,但它也应该与字符串一起使用。

    【讨论】:

    • 我已经阅读了这两个链接 - 第一个链接让我希望实际上将长字符串写入 blob 是可能的。关于不使用 SQL 的部分适用于 pre-0.9.4,所以我很好。第二个链接中的答案实际上是关于如何将二进制数据写入文件 - 在这一点上这是我想要的一个问题:)
    • 好的,你真的尝试过使用流吗?
    • 我不确定在 C# 中使用流写入 Firebird 数据库的记录在哪里 - 你能提供链接吗?
    • 我找到的所有链接都是针对 IBProvider 的。但是您使用的是 DotNetFirebird。不幸的是,我找不到有关流的任何信息。那么他们实际上是如何编写带有图像的 blob?
    猜你喜欢
    • 2021-03-25
    • 2018-05-13
    • 2010-10-10
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多