Как закачать большой текст через .NET провайдеры
Привет всем.
В качестве эксперимента по закачке больших объемов данных (например — текстовых), я создал следующий забавный пример на C#, передающий в стандартный OLEDB.NET и наш LCPI.OLEDB.NET провайдеры объект с интерфейсом IIBP_ISequenialStream_WideChar.
Здесь Test_LCPI_OLEDB_NET работает с нашим .NET провайдером, а Test_STD_OLEDB_NET — со стандартным. В первом случае код получается немного более компактный и работает с именованными параметрами.
Для простоты IBP_TextStreamReader работает с объектом string. Однако его можно переделать так, чтобы он, к примеру, читал и возвращал данные из текстового файла.
using System;
using System.Data;
using System.Diagnostics;
using System.Security;
using System.Runtime.InteropServices;
using com_lib=lcpi.lib.com;
using structure_lib=lcpi.lib.structure;
using xdb=lcpi.data.oledb;
using sdb=System.Data.OleDb;
namespace ConsoleApplication1
{
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[SuppressUnmanagedCodeSecurity]
[Guid("769A128F-04BF-11D8-AE8B-00A0C907DB93")]
public unsafe interface IIBP_ISequentialStream_WideChar
{
[PreserveSig]
com_lib.HResultCode Read([In] char* pchars,
[In] UIntPtr cch,
[In] UIntPtr* pcchRead);
[PreserveSig]
com_lib.HResultCode Write([In] char* pchars,
[In] UIntPtr cch,
[In] UIntPtr* pcchWritten);
};//interface IIBP_ISequentialStream_WideChar
//-----------------------------------------------------------------------
unsafe class IBP_TextStreamReader:IIBP_ISequentialStream_WideChar
{
public IBP_TextStreamReader(string text)
{
m_text=text;
m_pos=0;
}//IBP_TextStreamReader
//----------------------------------------------------------------------
[PreserveSig]
public com_lib.HResultCode Read([In] char* pchars,
[In] UIntPtr cch,
[In] UIntPtr* pcchRead)
{
if(cch!=UIntPtr.Zero && pchars==null)
return com_lib.HResultCode.E_INVALIDARG;
if(pcchRead!=null)
(*pcchRead)=UIntPtr.Zero;
Debug.Assert(m_pos>=0);
Debug.Assert(m_pos<=m_text.Length);
lock(m_guard)
{
if(m_pos==m_text.Length)
return com_lib.HResultCode.S_FALSE; //EOF
var tail_sz=structure_lib.to_unsigned.exec(m_text.Length-m_pos);
var ncch=System.Math.Min(structure_lib.uintptr_utils.ToNumeric(cch),
tail_sz);
fixed(char* ptext=m_text)
{
char* psrc=ptext+m_pos;
char* esrc=psrc+ncch;
char* pdest=pchars;
for(;psrc!=esrc;++pdest,++psrc)
{
(*pdest)=(*psrc);
}
}//fixed
if(pcchRead!=null)
(*pcchRead)=structure_lib.uintptr_utils.ToUIntPtr(ncch);
m_pos+=(int)ncch;
}//lock
return com_lib.HResultCode.S_OK;
}//Read
//----------------------------------------------------------------------
[PreserveSig]
public com_lib.HResultCode Write([In] char* pchars,
[In] UIntPtr cch,
[In] UIntPtr* pcchWritten)
{
if(cch!=UIntPtr.Zero && pchars==null)
return com_lib.HResultCode.E_INVALIDARG;
if(pcchWritten!=null)
(*pcchWritten)=UIntPtr.Zero;
return com_lib.HResultCode.E_NOTIMPL;
}//Write
//----------------------------------------------------------------------
private object m_guard=new object();
private string m_text;
private int m_pos;
};//class IBP_TextStreamReader
class Program
{
const string c_cn_str
="provider=LCPI.IBProvider.3;"
+"location=localhost:d:\\database\\ibp_test_fb25_d3.gdb;"
+"user id=gamer;"
+"password=vermut;"
+"ctype=utf8";
static void Main(string[] args)
{
try
{
Test_LCPI_OLEDB_NET();
Console.WriteLine("");
Test_STD_OLEDB_NET();
}
catch(Exception exc)
{
Console.WriteLine("ERROR: {0}",exc.Message);
}
Console.WriteLine("[DONE] Press Any Key");
Console.ReadKey(false);
}//Main
//-----------------------------------------------------------------------
static void Test_LCPI_OLEDB_NET()
{
try
{
Console.WriteLine("Test_LCPI_OLEDB_NET");
using(var cn=new xdb.OleDbConnection(c_cn_str))
{
Console.WriteLine("Connect to database ...");
cn.Open();
Console.WriteLine("Start transaction ...");
using(var tr=cn.BeginTransaction(IsolationLevel.RepeatableRead))
{
const string c_sql
="insert into TBL_CS__UTF8 (COL_BLOB) values(:a)\n"
+"returning COL_BLOB into :b";
using(var cmd=new xdb.OleDbCommand(c_sql,cn,tr))
{
Console.WriteLine("Receving a parameters from provider ...");
cmd.Parameters.Refresh();
cmd["a"].Value=new IBP_TextStreamReader(c_cn_str);
Console.WriteLine("Insert record ...");
cmd.ExecuteNonQuery();
object out_param_value=cmd["b"].Value;
if(out_param_value==DBNull.Value)
throw new ApplicationException("got the NULL value!");
if(c_cn_str!=(string)out_param_value)
throw new ApplicationException("got the unexpected value!");
Console.WriteLine("OK: we obtained back the our text.");
}//using cmd
Console.WriteLine("Commit transaction ...");
tr.Commit();
}//using tr
}//using cn
}
catch(Exception exc)
{
Console.WriteLine("ERROR: {0}",exc.Message);
}
}//Test_LCPI_OLEDB_NET
//-----------------------------------------------------------------------
static void Test_STD_OLEDB_NET()
{
try
{
Console.WriteLine("Test_STD_OLEDB_NET");
using(var cn=new sdb.OleDbConnection(c_cn_str))
{
Console.WriteLine("Connect to database ...");
cn.Open();
Console.WriteLine("Start transaction ...");
using(var tr=cn.BeginTransaction(IsolationLevel.RepeatableRead))
{
const string c_sql
="insert into TBL_CS__UTF8 (COL_BLOB) values(?)\n"
+"returning COL_BLOB into ?";
using(var cmd=new sdb.OleDbCommand(c_sql,cn,tr))
{
cmd.Parameters.Add(new sdb.OleDbParameter("",
sdb.OleDbType.Variant,
/*size*/0,
ParameterDirection.Input,
/*isNullable*/true,
/*precision*/0,
/*scale*/0,
null,
DataRowVersion.Current,
null));
cmd.Parameters.Add(new sdb.OleDbParameter("",
sdb.OleDbType.Variant,
/*size*/0,
ParameterDirection.Output,
/*isNullable*/true,
/*precision*/0,
/*scale*/0,
null,
DataRowVersion.Current,
null));
cmd.Parameters[0].Value=new IBP_TextStreamReader(c_cn_str);
Console.WriteLine("Insert record ...");
cmd.ExecuteNonQuery();
object out_param_value=cmd.Parameters[1].Value;
if(out_param_value==DBNull.Value)
throw new ApplicationException("got the NULL value!");
if(c_cn_str!=(string)out_param_value)
throw new ApplicationException("got the unexpected value!");
Console.WriteLine("OK: we obtained back the our text.");
}//using cmd
Console.WriteLine("Commit transaction ...");
tr.Commit();
}//using tr
}//using cn
}
catch(Exception exc)
{
Console.WriteLine("ERROR: {0}",exc.Message);
}
}//Test_STD_OLEDB_NET
};//class Program
}//namespace ConsoleApplication1
На выходе получаем:

С одной стороны — вроде как ничего военного. А с другой — ЭТО ПОБЕДА! 🙂