Как закачать большой текст через .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
На выходе получаем:
С одной стороны — вроде как ничего военного. А с другой — ЭТО ПОБЕДА! 🙂