最終更新日: $Date: 2007/05/31 09:31:53 $ by $Author: fxjr $
範疇: 外部ドキュメント
意図する読者: Npgsql ユーザの皆さん
日本語翻訳著作権 ©: ishikawa[at]postgresql.jp/z-saito[at]guitar.ocn.ne.jp
Npgsql は Postgresql Database Server に対する .Net データプロバイダです。
PostgreSQL サーバがデータを送ったり、受け取ったりするために使用する .Net クライアントアプリケーション(コンソール、WinForms、ASP.NET、Web サービスなど)を提供します。MS.Net および Mono 用にコンパイルされた Npgsql はプロジェクトのファイル欄から入手できます。
このパッケージの中は以下のディレクトリ構造になっています。
Npgsql/bin/docs - ドキュメント
Npgsql/bin/docs/apidocs - API ドキュメント
Npgsql/bin/ms1.1 - MS.Net 1.1 用にコンパイルされた Npgsql
Npgsql/bin/mono - Mono 用にコンパイルされた Npgsql
そのほかのプラットフォーム、もしくは別のバージョン用として Npgsql が公開された時は、遅滞なくこのディレクトリ構造の中に追加されます。
.Net ランタイムが Npgsql.dll ライブラリを見つけられるようにするには、このファイルはアプリケーションと同一のディレクトリに置く必要があります。但し、構成ファイルから(探査要素 で)ほかのディレクトリを個人コンポーネントのパスとして指定した場合はこの限りではありません。どのようにランタイムが読み込む必要のあるアセンブリを 探査する(場所を探し当てる)かについては .Net のドキュメントを参照ください。
ASP.NET および Web サービス、.Net アプリケーションにおいて、「bin」ディレクトリが ASP.NET ルートアプリケーションディレクトリの下に存在しなければなりません。
Npgsql アセンブリを Global Cache アセンブリ内に置くことも可能です。バージョン 0.4 以降、インストールに gacutil を使用することで認知のさせ方が強固になっています。これを行うには以下のコマンドを発行します:
gacutil -i Npgsql.dll
これ以上のヘルプは MSDN ドキュメントの「Installing an Assembly in the Global Cache Assembly」をぜひ参照してください。
別の手法として、常に Npgsql.dll をコピーする必要なく全てのアプリケーションをアクセス可能にするため、Npgsql を GAC (Global Assembly Cache:グローバルアセンブリキャッシュ) にインストールすることも可能です。Npgsql で設計されている時刻のサポートを VS.Net で使用したい場合、Npgsql を GAC に置く必要があることに注意してください。
Mono 用にコンパイルされた Npgsql は既に Mono ランタイムに Mono.Security.dll が入っていますので、新たに手当ての必要はありません。
これでサンプルをやってみれる準備が整いました。3 章に飛んでください。
Npgsql を cvs から取得するには以下の手順を使用している cvs クライアントから実行します:
Server: cvs.pgfoundry.orgコマンドラインで cvs を使用しているのであれば、以下のように単純です:
cvs -d :pserver:anonymous@cvs.pgfoundry.org:/cvsroot/npgsql login
cvs -d :pserver:anonymous@cvs.pgfoundry.org:/cvsroot/npgsql checkout Npgsql
コードの入手が始まります:
$ cvs -d :pserver:anonymous@cvs.pgfoundry.org:/cvsroot/npgsql login Logging in to :pserver:anonymous@cvs.pgfoundry.org:2401/cvsroot/npgsql CVS password: $ cvs -d :pserver:anonymous@cvs.pgfoundry.org:/cvsroot/npgsql co Npgsql cvs checkout: Updating Npgsql cvs checkout: Updating Npgsql/admin U Npgsql/admin/release.pl cvs checkout: Updating Npgsql/docs U Npgsql/docs/Npgsql.zargo U Npgsql/docs/NpgsqlConnectionStateMachine.png U Npgsql/docs/SuggestedReadings.htm ...
Npgsql をコンパイルするのに公式なサポートを受けたいのであれば NAnt を使用してください。
Npgsql/src/Npgsql フォルダで nant を実行するだけです。
nunit のテスト実行は nant tests を呼ぶだけです。
VS.Net、SharpDevelop、および MonoDevelop のような他の開発プラットフォームに対するソリューションプロジェクトを提供する予定です。既にいくつかのソリューションプロジェクトを入手していますの で、それらが近い将来に使えるよう開発チームは努力しています。
注意:Npgsql は今でも開発途中です。現在サポートされている特徴のみ説明します。Npgsql が成熟にするにつれ、使用できる機能が増えてゆくでしょう。
最初に、Npgsql オブジェクトをより用意に扱うため、コンパイラに Npgsql 名前空間の使用を伝えなければ成りません。同時に、System.Data 名前空間も使用する必要があります。と言うのは、データ操作に使用される数多くのクラスがその中に駐在するからです。これを行うために、C# では次の指示文を使用します:
using System.Data; using Npgsql;
ASP.NET を使用する場合、.aspx ページの一番初めに以下の行を書き入れます:
<Assembly name="System.Data"> <Assembly name="Npgsql">これについてのより詳細は、FAQ Mono Page about ASP.NET にあります。
using System; using System.Data; using Npgsql; public class NpgsqlUserManual { public static void Main(String[] args) { NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=joe;Password=secret;Database=joedata;"); conn.Open(); conn.Close(); } }
接続を確立するとき、NpgsqlConnection はその振る舞いを変更するために使用する数多くのパラメータを受け付けます。以下はプログラムの微調整を行う現在のパラメータを一覧表です。
PostgreSQL データベースに接続するために使用される文字列を取得、もしくは設定します。 /// 有効な値: /// Server: Postgresql サーバのアドレス/名称 /// Port: 接続するポート /// Protocol: 自動ではなく、使用されるプロトコルバージョン;整数2もしくは3 /// User Id: ユーザ名 /// Password: 平文認証用のパスワード /// SSL: 真、もしくは偽。安全な接続を行うか否かの制御。デフォルト=偽 /// Pooling: 真、もしくは偽。接続プールを使用するか否かの制御。デフォルト=真 /// Encoding: 使用される符号化方式。ASCII もしくは UNICODE。デフォルトは ASCII。アクセント符号に問題があれば UNICODE を使用してください /// CommandTimeout: 例外を投げる前にコマンドが実効を終了するまでの待ち時間。秒単位。デフォルトは20 /// Sslmode: SSL 接続制御モード /// ConnectionLifeTime: 秒単位の、プール内非使用接続を閉じるまでの待ち時間。デフォルトは15 /// SyncNotification: Npgsql が同期式通知を使用するかどうかの指定 符号化方式は ASCII もしくは UNICODE です。使用しているアプリケーションがデフォルトでアクセント記号をもった文字の場合動きません。変更を試みてください。 最小プールサイズが指定された場合、NpgsqlConnection はサーバ接続に際してその数字を事前に割り当てます。 Sslmode は以下の値の内の一つです: Prefer - 可能であれば ssl を使用して接続します。 Require - ssl 接続ができない場合、例外が投げられます。 Allow - まだサポートされていません。ssl なしで接続されます。 Disable - ssl 接続は行われません。 Default は Disable です。
using System; using System.Data; using Npgsql; public static class NpgsqlUserManual { public static void Main(String[] args) { NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=joe;Password=secret;Database=joedata;"); conn.Open(); NpgsqlCommand command = new NpgsqlCommand("insert into table1 values(1, 1)", conn); Int32 rowsaffected; try { rowsaffected = command.ExecuteNonQuery(); } Console.WriteLine("It was added {0} lines in table table1", rowsaffected); finally { conn.Close(); } } }
using System; using System.Data; using Npgsql; public static class NpgsqlUserManual { public static void Main(String[] args) { NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=joe;Password=secret;Database=joedata;"); conn.Open(); NpgsqlCommand command = new NpgsqlCommand("select version()", conn); String serverversion; try { serverversion = (String)command.ExecuteScalar(); } Console.WriteLine("PostgreSQL server version: {0}", serverversion); finally { conn.Close(); } } }ほかの問い合わせも使用できます。たとえば「select count(*) from table1」です。同時に、単一の値を返さない問い合わせも使用できますが、最初の行の最初の列の値のみが返されることになります。
問い合わせから全ての結果を戻す命令を実行するには、NpgsqlCommand オブジェクトの ExecuteReader() メソッドを使用します:
using System; using System.Data; using Npgsql; public static class NpgsqlUserManual { public static void Main(String[] args) { NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=joe;Password=secret;Database=joedata;"); conn.Open(); NpgsqlCommand command = new NpgsqlCommand("select * from tablea", conn); try { NpgsqlDataReader dr = command.ExecuteReader(); while(dr.Read()) { for (i = 0; i < dr.FieldCount; i++) { Console.Write("{0} \t", dr[i]); } Console.WriteLine(); } } finally { conn.Close(); } } }このコードはデータベースに tablea というテーブルが存在することを仮定します。
警告:ExecuteReader と大きなテーブルを呼ぶときには知られた問題が存在します。現時点で Npgsql は全てのデータをテーブルから返す前に取得します。このような場合、性能の悪さを経験したなら、ページから行にわたってサーバカーソルを使用する必要があ ります。それに対しては、以下のようなコードが使用できます:
using System; using System.Data; using Npgsql; public static class NpgsqlUserManual { public static void Main(String[] args) { NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=joe;Password=secret;Database=joedata;"); conn.Open(); NpgsqlCommand command = new NpgsqlCommand("declare te cursor for select * from tablea;", _conn); command.ExecuteNonQuery(); command.CommandText = "fetch forward 3 in te;"; NpgsqlDataReader dr = command.ExecuteReader(); while (dr.Read()) { //ここでデータを操作 } dr.Close(); // さらに3行セット dr = command.ExecuteReader(); while (dr.Read()) { //ここでデータを操作 } dr.Close(); } }
次のバージョンではこれが自動的に行われるように作業をしています。
NpgsqlParamenter および NpgsqlParamenterCollection オブジェクトを使用して、サーバにパラメータ化された問い合わせを送ることもできます。パラメータは問い合わせ文字列の中で : から始まる文字列です。次の例は column1 と呼ばれるパラメータを使用しています。
using System; using System.Data; using Npgsql; public static class NpgsqlUserManual { public static void Main(String[] args) { NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=joe;Password=secret;Database=joedata;"); conn.Open(); // 問い合わせ文字列内でパラメータを宣言 NpgsqlCommand command = new NpgsqlCommand("select * from tablea where column1 = :column1", conn); // ここでコマンドのパラメータを、パラメータの型を指定してパラメータ蒐集に追加 command.Parameters.Add(new NpgsqlParameter("column1", DbType.Int32)); // ここで値を追加し、いつものように後でコマンドを実行 command.Parameters[0].Value = 4; try { NpgsqlDataReader dr = command.ExecuteReader(); while(dr.Read()) { for (i = 0; i < dr.FieldCount; i++) { Console.Write("{0} \t", dr[i]); } Console.WriteLine(); } } finally { conn.Close(); } } }このコードは tablea という名前のテーブルに、少なくとも一つの int4 型を持つ column1 という列が存在することを想定しています。
上の例は、サーバにプリペアード命令リクエストを送信するために使用することもできます。このようにして、問い合わせ計画はたった一度だけ作成さ れ、それ以降の呼び出しに対し再利用されます。この機能は 7.3 以降のサーバで有効である点を覚えておいてください。7.3 以前のこの機能をサポートしていないサーバ内で呼び出した場合、Npgsql は警告を出さず、単に無視します。呼び出しを行うコードを作成した場合でも、サポートしているサーバのみに効力を及ぼすという点で好ましいものです。これ を行うには、単にコマンドの Prepare() メソッドを呼び出します。
using System; using System.Data; using Npgsql; public static class NpgsqlUserManual { public static void Main(String[] args) { NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=joe;Password=secret;Database=joedata;"); conn.Open(); // 問い合わせ文字列内でパラメータを宣言 NpgsqlCommand command = new NpgsqlCommand("select * from tablea where column1 = :column1", conn); // ここでコマンドのパラメータを、パラメータの型を指定してパラメータ蒐集に追加 command.Parameters.Add(new NpgsqlParameter("column1", DbType.Int32); // ここで命令を準備 command.Prepare(); // ここで値を追加し、いつものように後でコマンドを実行 command.Parameters[0].Value = 4; try { NpgsqlDataReader dr = command.ExecuteReader(); while(dr.Read()) { for (i = 0; i < dr.FieldCount; i++) { Console.Write("{0} \t", dr[i]); } Console.WriteLine(); } } finally { conn.Close(); } } }このコードは tablea という名前のテーブルに、少なくとも一つの int4 型を持つ column1 という列が存在することを想定しています。
出力パラメータを Npgsql で使用することができます。Npgsql は、問い合わせの実行による最初の結果セットを構文解析し、出力パラメータの値に翻訳することにより、出力パラメータを「シミュレート」します。これは2 つの方法、つまりマップするか、しないかです。マップ構文解析は、結果セットでパラメータに返された列名を、同じ名前で合致するか試みます。合致すると、 合致した出力パラメータのみ更新されます。もしマップが見つからない場合、出力パラメータは、コマンドパラメータ蒐集に加えられた順に基づいて更新されま す。このマッピングは自動的に行われます。結果セットを構文解析する場合、Npgsql はマッチを見つける試みを行います。出力、および入出力パラメータの方向は共にサポートされています。
using System; using System.Data; using Npgsql; public static class NpgsqlUserManual { public static void Main(String[] args) { NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=joe;Password=secret;Database=joedata;"); conn.Open(); // バックエンドに問い合わせを送る NpgsqlCommand command = new NpgsqlCommand("select * from tablea where column1 = 2", conn); // ここで tablea の最初の列を受け取る出力パラメータを宣言 NpgsqlParameter firstColumn = new NpgsqlParameter("firstcolumn", NpgsqlDbType.Integer); firstColumn.Direction = ParameterDirection.Output; command.Parameters.Add(firstColumn); try { command.ExecuteNonQuery(); // ここで firstcolumn パラメータは結果セットの最初の列の値を所有する Console.WriteLine(firstColumn.Value); } finally { conn.Close(); } } }
関数を呼び出すためには、NpgsqlCommand オブジェクトの CommandType 所有権を CommandType.StoredProcedure に設定し、呼び出したい関数の名前を問い合わせ文字列として渡すだけです。
using System; using System.Data; using Npgsql; // この例は以下で定義された func() と呼ばれる関数を使用します: // create function funcC() returns int8 as ' // select count(*) from tablea; // ' language 'sql'; // バージョン 7.3 以降、select count(*) の戻り値型は int4 から int8 に変更されたことを覚えておいてください。 // この関数を、バージョン 7.2 サーバで使用するときは、戻り値型を int8 から int4 に変更してください。 public static class NpgsqlUserManual { public static void Main(String[] args) { NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=joe;Password=secret;Database=joedata;"); conn.Open(); try { NpgsqlCommand command = new NpgsqlCommand("funcC()", _conn); command.CommandType = CommandType.StoredProcedure; Object result = command.ExecuteScalar(); Console.WriteLine(result); } finally { conn.Close(); } } }
明瞭な問い合わせと同様に、パラメータを関数呼び出しに指定できます。
using System; using System.Data; using Npgsql; // T // create function funcC(int4) returns int8 as ' // select count(*) from tablea where field_int4 = $1; // ' language 'sql'; public static class NpgsqlUserManual { public static void Main(String[] args) { NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=joe;Password=secret;Database=joedata;"); conn.Open(); try { NpgsqlCommand command = new NpgsqlCommand("funcC(:a)", _conn); command.CommandType = CommandType.StoredProcedure; command.Parameters.Add(new NpgsqlParameter("a", DbType.Int32)); command.Parameters[0].Value = 4; Object result = command.ExecuteScalar(); Console.WriteLine(result); } finally { conn.Close(); } } }
このコードは tablea という名前のテーブルに、少なくとも一つの int4 型を持つ field_int4 という列が存在することを想定しています。
データセットを扱うときに Npgsql を使用できます。このことにより、データセットを変更し、バックエンドに戻して反映させることができます。以下の例はデータセットを使用してどのように行を追加するかを示しています。
// このメソッドはバックエンドに次のテーブルが存在することを想定します: // // create table tableb(field_int2 int2, field_timestamp timestamp, field_numeric numeric); // // void AddWithDataSet(NpgsqlConnection conn) { conn.Open(); DataSet ds = new DataSet(); NpgsqlDataAdapter da = new NpgsqlDataAdapter("select * from tableb", conn); da.InsertCommand = new NpgsqlCommand("insert into tableb(field_int2, field_timestamp, field_numeric) " + " values (:a, :b, :c)", conn); da.InsertCommand.Parameters.Add(new NpgsqlParameter("a", DbType.Int16)); da.InsertCommand.Parameters.Add(new NpgsqlParameter("b", DbType.DateTime)); da.InsertCommand.Parameters.Add(new NpgsqlParameter("c", DbType.Decimal)); da.InsertCommand.Parameters[0].Direction = ParameterDirection.Input; da.InsertCommand.Parameters[1].Direction = ParameterDirection.Input; da.InsertCommand.Parameters[2].Direction = ParameterDirection.Input; da.InsertCommand.Parameters[0].SourceColumn = "field_int2"; da.InsertCommand.Parameters[1].SourceColumn = "field_timestamp"; da.InsertCommand.Parameters[2].SourceColumn = "field_numeric"; da.Fill(ds); DataTable dt = ds.Tables[0]; DataRow dr = dt.NewRow(); dr["field_int2"] = 4; dr["field_timestamp"] = new DateTime(2003, 03, 03, 14, 0, 0); dr["field_numeric"] = 7.3M; dt.Rows.Add(dr); DataSet ds2 = ds.GetChanges(); da.Update(ds2); ds.Merge(ds2); ds.AcceptChanges(); }
この例は xsd で生成された Strong と型づけされたデータセットの扱いを示しています。このためには、Strong データセットに対するスキーマを指定した .xsd ファイルが必要になります。このファイルを手作業で生成するか、もしくは手作業に代わって xsd に .xsd を生成させることもできます。xsd に .xsd を生成させるには、どこに .xsd があるのかを推測させる手立てを .xml ファイルで提供する必要があります。DataAdapter.WriteXml() メソッドにより生成される .xml ファイルが使用できます:
public void GenerateXmlFromDataSet(NpgsqlConnection conn) { conn.Open(); NpgsqlDataAdapter da = new NpgsqlDataAdapter("select * from tablea", conn); DataSet ds = new DataSet(); da.Fill(ds); ds.WriteXml("StrongDataSetFeed.xml"); }
これにより、以下とよく似たファイルができます:
<?xml version="1.0" standalone="yes"?> <NewDataSet> <Table> <field_serial>1</field_serial> <field_text>Random text</field_text> </Table> <Table> <field_serial>2</field_serial> <field_int4>4</field_int4> </Table> <Table> <field_serial>3</field_serial> <field_int8>8</field_int8> </Table> <Table> <field_serial>4</field_serial> <field_bool>true</field_bool> </Table> <Table> <field_serial>5</field_serial> <field_text>Text with ' single quote</field_text> </Table> </NewDataSet>
このファイルは以下のコマンドを使用し、.xsd ファイルを生成する xsd で使用されます:
xsd StrongDataSetFeed.xml
xsd は文字列として指定される全ての型を所有する xml スキーマを作成します。間違いのない型を使用するように xsd を変更するだけで、以下と類似した .sxd ファイルを得ることができます。
<?xml version="1.0" encoding="utf-8"?> <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:Locale="pt-BR"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element name="Table"> <xs:complexType> <xs:sequence> <xs:element name="field_serial" type="xs:int" minOccurs="0" /> <xs:element name="field_text" type="xs:string" minOccurs="0" /> <xs:element name="field_int4" type="xs:int" minOccurs="0" /> <xs:element name="field_int8" type="xs:long" minOccurs="0" /> <xs:element name="field_bool" type="xs:boolean" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:schema>
このファイルを使って、xsd が Strong データセットを生成させる以下のコマンドを発行します:
xsd StrongDataSetFeed.xsd /dataset
これは、Strong データセットを持ったアセンブリを得るためにコンパイルできるようなファイルを生成させます
using System; using Npgsql; public class t { public static void Main(String[] args) { NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=joe;Password=secret;Database=joedata;"); conn.Open(); NpgsqlDataAdapter da = new NpgsqlDataAdapter("Select * from tablea", conn); NewDataSet n = new NewDataSet(); da.Fill(n); foreach (NewDataSet._TableRow tr in n._Table) { Console.WriteLine(tr.field_serial); } } }
この例はファイル名を引数として、その内容を、bytea 型の field_bytea というフィールドと、シリアル型の field_serial というフィールドを所有した、tableByteA と呼ばれるテーブルに挿入します。後でその内容を取得し、終わりに「database」と付けられた新規ファイルを書き出します。
テーブルスキーマ: create table tableBytea (field_serial serial, field_bytea bytea)
using System; using System.Data; using Npgsql; using System.IO; public class t { public static void Main(String[] args) { //NpgsqlEventLog.Level = LogLevel.Debug; //NpgsqlEventLog.LogName = "NpgsqlTests.LogFile"; NpgsqlConnection conn = new NpgsqlConnection("server=localhost;user id=npgsql_tests;password=npgsql_tests"); conn.Open(); FileStream fs = new FileStream(args[0], FileMode.Open, FileAccess.Read); BinaryReader br = new BinaryReader(new BufferedStream(fs)); Byte[] bytes = br.ReadBytes((Int32)fs.Length); Console.WriteLine(fs.Length); br.Close(); fs.Close(); NpgsqlCommand command = new NpgsqlCommand("insert into tableBytea(field_bytea) values(:bytesData)", conn); NpgsqlParameter param = new NpgsqlParameter(":bytesData", DbType.Binary); param.Value = bytes; command.Parameters.Add(param); command.ExecuteNonQuery(); command = new NpgsqlCommand("select field_bytea from tableBytea where field_serial = (select max(select field_serial) from tableBytea);", conn); Byte[] result = (Byte[])command.ExecuteScalar(); fs = new FileStream(args[0] + "database", FileMode.Create, FileAccess.Write); BinaryWriter bw = new BinaryWriter(new BufferedStream(fs)); bw.Write(result); bw.Flush(); fs.Close(); bw.Close(); conn.Close(); } }
この例は bytea コードをサポートする上記と同じです。異なる部分は PostgreSQL のラージオブジェクトサポートを使用することです。この例は postgresql にファイルを挿入し、あとで削除します。bytea の例のように、「database」を後ろに付けてファイルを書き出します。
using System; using System.Data; using Npgsql; using NpgsqlTypes; using System.IO; public class c { public static void Main(String[] args) { NpgsqlConnection newconn = new NpgsqlConnection("server=localhost;user id=npgsql_tests;password=npgsql_tests"); newcon.Open(); NpgsqlTransaction t = newcon.BeginTransaction(); LargeObjectManager lbm = new LargeObjectManager(newcon); int noid = lbm.Create(LargeObjectManager.READWRITE); LargeObject lo = lbm.Open(noid,LargeObjectManager.READWRITE); FileStream fs = File.OpenRead(args[0]); byte[] buf = new byte[fs.Length]; fs.Read(buf,0,(int)fs.Length); lo.Write(buf); lo.Close(); t.Commit(); t = newcon.BeginTransaction(); lo = lbm.Open(noid,LargeObjectManager.READWRITE); FileStream fsout = File.OpenWrite(args[0] + "database"); buf = lo.Read(lo.Size()); fsout.Write(buf, 0, (int)lo.Size()); fsout.Flush(); fsout.Close(); lo.Close(); t.Commit(); DeleteLargeObject(noid); Console.WriteLine("noid: {0}", noid); newcon.Close(); } public static void DeleteLargeObject(Int32 noid) { NpgsqlConnection conn = new NpgsqlConnection("server=localhost;user id=npgsql_tests;password=npgsql_tests"); newcon.Open(); NpgsqlTransaction t = newcon.BeginTransaction(); LargeObjectManager lbm = new LargeObjectManager(newcon); lbm.Delete(noid); t.Commit(); newcon.Close(); } }
Mirek(mirek at mascort dot com dot pl)が寄稿した他の例では、データベースから画像を取り出して、フォームとして表示するラージオブジェクトを使います。
using System; using Npgsql; using NpgsqlTypes; using System.Drawing; using System.IO; //データベースから画像の oid を取得するメソッド public int takeOID(int id) { //データベースに接続し、画像 oid を返すメソッド BazySQL pir = new BazySQL(Login.DaneUzera[8]); string pytanko = String.Format("select rysunek from k_rysunki where idtowaru = " + idtowaru.ToString()); string[] wartosci = pir.OddajSelectArray(pytanko); int liczba = int.Parse(wartosci[0].ToString()); return liczba; } //データベースから画像を取得し、それを Image 型に変換 public Image pobierzRysunek(int idtowaru) { NpgsqlConnection Polacz = new NpgsqlConnection(); Polacz.ConnectionString = Login.DaneUzera[8].ToString(); //its metod whos return connection string Polacz.Open(); NpgsqlTransaction t = Polacz.BeginTransaction(); LargeObjectManager lbm = new LargeObjectManager(Polacz); LargeObject lo = lbm.Open(takeOID(idtowaru),LargeObjectManager.READWRITE); //take picture oid from metod takeOID byte[] buf = new byte[lo.Size()]; buf = lo.Read(lo.Size()); MemoryStream ms = new MemoryStream(); ms.Write(buf,0,lo.Size()); lo.Close(); t.Commit(); Polacz.Close(); Polacz.Dispose(); Image zdjecie = Image.FromStream(ms); return zdjecie; } //次はこのメソッドを使用するだけです。 pictureBox1.Image = Image pobierzRysunek(1);
この例は refcursor を返す関数からデータを取得する方法を示しています。Npgsql で提供されるサポートにより、refcursor をどのように扱うかを考慮せず、これらの関数から数多くの結果セットを取得できます。
例を示す目的として、以下の refcursor 返還関数を検討します。
CREATE OR REPLACE FUNCTION testrefcursor() RETURNS SETOF refcursor AS 'DECLARE ref1 refcursor; ref2 refcursor; BEGIN OPEN ref1 FOR SELECT 1; RETURN NEXT ref1; OPEN ref2 FOR SELECT 2; RETURN next ref2; RETURN; END;' LANGUAGE plpgsql;
この関数は単に一行の resultset を返すだけという事実に注目してください。好きなように select 1 をどのような select にも変更できます。
では、これらの関数を呼ぶのとデータを抽出するのに以下のコードを使ってみます:
using System; using System.Data; using Npgsql; using NpgsqlTypes; public class c { public static void Main(String[] args) { NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Initial Catalog=eeeeee;User id=npgsql_tests;password=npgsql_tests;"); conn.Open(); NpgsqlTransaction t = conn.BeginTransaction(); NpgsqlCommand command = new NpgsqlCommand("testrefcursor", conn); command.CommandType = CommandType.StoredProcedure; NpgsqlDataReader dr = command.ExecuteReader(); while(dr.Read()) { Console.WriteLine(dr.GetValue(0)); } dr.NextResult(); while(dr.Read()) { Console.WriteLine(dr.GetValue(0)); } dr.Close(); t.Commit(); conn.Close(); } }
これで全てです。最後に一つ注意しておくことは、これを動作させるにはトランザクションを使用しなければならないことです。これは、関数呼び出しを行った後、明示的なトランザクションを閉じることによって refcursor 関数から返されるカーソルを保全する必要があるためです。
関数の中にパラメータがある場合、コマンドテキストで関数名だけをそれでも入れて、いつものように NpgsqlCommand.Parameters 蒐集にパラメータを追加する必要があります。Npgsql は使用するパラメータを正しく処理します。
この例は Npgsql Forums において user question に回答する形で Josh Cooley により寄稿されたものです。このコードは、データベースに以下のようなテーブルと関数があることを想定しています。
create table test_seq (field_serial serial, test_text text); CREATE OR REPLACE FUNCTION ins_seq("varchar") RETURNS test_seq AS 'insert into test_seq (test_text) values ($1); select * from test_seq where test_text = $1' LANGUAGE 'sql' VOLATILE;
そしてこれがコードです:
using System; using System.Data; using Npgsql; using NpgsqlTypes; public class c { public static void Main(String[] args) { //NpgsqlEventLog.Level = LogLevel.Debug; //NpgsqlEventLog.LogName = "NpgsqlTests.LogFile"; //NpgsqlEventLog.EchoMessages = true; NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;User id=npgsql_tests;password=npgsql_tests;"); using (NpgsqlDataAdapter adapter = new NpgsqlDataAdapter("select * from test_seq", conn)) { DataTable table = new DataTable(); adapter.Fill(table); adapter.InsertCommand = new NpgsqlCommand("ins_seq", adapter.SelectCommand.Connection); adapter.InsertCommand.Parameters.Add("foo", NpgsqlTypes.NpgsqlDbType.Varchar, 100, "test_text"); adapter.InsertCommand.CommandType = CommandType.StoredProcedure; DataRow row = table.NewRow(); row["test_text"] = "asdfqwert"; table.Rows.Add(row); adapter.Update(table); foreach (DataRow rowItem in table.Rows) { Console.WriteLine("key {0}, value {1}", rowItem[0], rowItem[1]); } Console.ReadLine(); } } }
Npgsql は処理中のコマンドを中止するようサーバに請求できます。これを行うためには、NpgsqlCommand の Cancel メソッドを呼び出す必要があります。メインスレッドはコマンドの終了を待っていることでブロックされるため、別のスレッドで行わなければならないことに注 意してください。同時に、このメインスレッドはユーザによるキャンセルで例外を引き起こすことがあります。エラーコードは 57014 です。以下にどのようにするかのサンプルコードを示します。
using System; using System.Data; using Npgsql; using NpgsqlTypes; using System.Threading; public class c { // このメソッドは以下のテーブルがバックエンドに存在することを前提にします: // /* CREATE OR REPLACE FUNCTION funcwaits() returns integer as ' declare t integer; begin t := 0; while t < 1000000 loop t := t + 1; end loop; return t; end; ' */ static NpgsqlConnection conn = null; static NpgsqlCommand command = null; public static void Main(String[] args) { //NpgsqlEventLog.Level = LogLevel.Debug; //NpgsqlEventLog.LogName = "NpgsqlTests.LogFile"; //NpgsqlEventLog.EchoMessages = true; try { conn = new NpgsqlConnection("Server=127.0.0.1;User id=npgsql_tests;password=npgsql_tests;"); conn.Open(); NpgsqlCommand d = new NpgsqlCommand(); Thread t = new Thread(new ThreadStart(CancelRequest)); command = new NpgsqlCommand("select * from funcwaits()", conn); Console.WriteLine("Cancelling command..."); t.Start(); Console.WriteLine(command.ExecuteScalar()); conn.Close(); } catch(NpgsqlException e) { if (e.Code == "57014") Console.WriteLine("Command was cancelled"); } } public static void CancelRequest() { command.Cancel(); Console.WriteLine("command cancelled"); } }
Npgsql はバックエンドサーバによって送られる通知に基づいた事象の受け取りをユーザに許可します。Npgsqlでそれらを受け取るには2つの方法があります:非 同期方式と同期方式です。同期式通知のみが Npgsql 1.0 およびそれ以降でサポートされています。
using System; using System.Data; using Npgsql; using NpgsqlTypes; using System.Threading; public class c { public static void Main(String[] args) { conn = new NpgsqlConnection("Server=127.0.0.1;User id=npgsql_tests;password=npgsql_tests;"); conn.Open(); NpgsqlCommand command = new NpgsqlCommand("listen notifytest;", conn); command.ExecuteNonQuery(); conn.Notification += new NotificationEventHandler(NotificationSupportHelper); command = new NpgsqlCommand("notify notifytest;", _conn); command.ExecuteNonQuery(); Console.ReadLine(); // 通知が処理される以前にプログラムが停止することを避けます。 } private void NotificationSupportHelper(Object sender, NpgsqlNotificationEventArgs args) { // ここで通知を処理します。 } }
このコードは通知を監視することを登録し、NotificationSupportHelper メソッドに通知が渡されるかのテストのために通知を出します。
エラーを追跡するため、Npgsql の振る舞いをたどる必要がしばしばあります。Npgsql にはログメッセージを指定されたファイル、もしくはコンソール、またはその両方に落とすことができます。
3種類のログ取得レベルがあります:
以下の NpgsqlEventLog の静的特性も同時に使用できます:
以下の例は、デバッグレベルでどのようにコンソールとファイルにログを取るかを示しています:
using System.Data; using Npgsql; public static class NpgsqlUserManual { public static void Main(String[] args) { // ログ取得を有効にする。 NpgsqlEventLog.Level = LogLevel.Debug; NpgsqlEventLog.LogName = "NpgsqlTests.LogFile"; NpgsqlEventLog.EchoMessages = true; NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=joe;Password=secret;Database=joedata;"); conn.Open(); conn.Close(); } }
このコードを実行すると次の出力が得られます:
Set NpgsqlEventLog.EchoMessages = True Entering NpgsqlConnection.NpgsqlConnection() Entering NpgsqlConnection.ParseConnectionString() Connection string option: DATABASE = joedata Connection string option: SERVER = 127.0.0.1 Connection string option: USER ID = joe Connection string option: PASSWORD = secret Entering NpgsqlConnection.Open() Connected to: 127.0.0.1:5432 Entering NpgsqlConnection.WritestartupPacket() Entering NpgsqlStartupPacket.NpgsqlStartupPacket() Entering NpgsqlStartupPacket.WriteToStream() Entering PGUtil.WriteLimString() Entering PGUtil.WriteLimString() Entering PGUtil.WriteLimString() Entering PGUtil.WriteLimString() Entering PGUtil.WriteLimString() Entering NpgsqlConnection.HandleStartupPacketResponse() AuthenticationRequest message from Server Server requested cleartext password authentication. Entering NpgsqlPasswordPacket.NpgsqlPasswordPacket() Entering NpgsqlPasswordPacket.WriteToStream() Entering PGUtil.WriteString() Listening for next message AuthenticationRequest message from Server Listening for next message BackendKeyData message from Server Entering NpgsqlBackEndKeyData.ReadFromStream() Got ProcessID. Value: 3116 Got SecretKey. Value: -132883070 Listening for next message ReadyForQuery message from Server Listening for next message Connection completed Entering NpgsqlConnection.Close()
多くの情報が取得できることを示すためにデバッグレベルを使用しました。もちろん、通常レベルでは出力はより少なくなります。同時に、同じ情報は NpgsqlTests.LogFile ファイル追加されます。
Npgsql 0.6
およびそれ以上のバージョンは初期デザイン時刻サポートを提供します。これが意味するところは、SqlConnections もしくは
OleDbConnections を使用している限り、Visual Studio .NET の Form-Designer に
NpgsqlConnection をドラッグ・アンド・ドロップできるということです。
同時に、ConnectionString を編集し検証する Dialog もあります。
そのようにするためには、以下が必要です:
結果として、Toolbox の Data タブに NpgsqlConnection というアイコンができます。
Npgsql は接続に問題を発見したときはいつでも全ての接続をプールから削除します。これは接続がプールにある間起こりうるいかなる不安定性問題からの回復を容易に します。ほかの接続が依然としてOKなので、この戦略は最善の性能をもたらさないとは言え、この振る舞いはプールが問題に際しても一貫性を保つことを保障 します。NpgsqlConnection を通じてプールを削除する2つの方法があります:ClearPool と ClearAllPools です。これらを使用して手作業でプールを削除可能です。
Npgsql は以下のデータ型をサポートしています:
Postgresql 型 | NpgsqlDbType | System.DbType Enum | .Net システム型 |
int8 | Bigint | Int64 | Int64 |
bool | Boolean | Boolean | Boolean |
Box, Circle, Line, LSeg, Path, Point, Polygon | Box, Circle, Line, LSeg, Path, Point, Polygon | Object | Object |
bytea | Bytea | Binary | Byte[] |
date | Date | Date | DateTime |
float8 | Double | Double | Double |
int4 | Integer | Int32 | Int32 |
money | Money | Decimal | Decimal |
numeric | Numeric | Decimal | Decimal |
float4 | Real | Single | Single |
int2 | Smallint | Int16 | Int16 |
text | Text | String | String |
time, timetz | Time | Time | DateTime |
timestamp | Timestamp | DateTime | DateTime |
timestamptz | TimestampTZ | DateTime | DateTime |
varchar | Varchar | String | String |
inet | Inet | Object | NpgsqlInet、IPAddress (IPAddress を使用する必要があって、NpgsqlInet のみ保有するのであれば、NpgsqlInet オブジェクトを IPAddress に変換する暗黙的キャスト演算子があります。) |
bit | Bit | Boolean | Boolean、Int32 (Int32 値を使う場合、奇数値はビット 1 に翻訳され、偶数値はビット 0 に翻訳されます。) |