# Npgsql: User's Manual

Copyright © The Npgsql Development Team

Last update: $Date: 2005/05/26 20:34:03 $ by $Author: fxjr $

Category: External documentation

Intended Audience: Npgsql Users

## 1. What is Npgsql?

Npgsql is a .Net Data Provider for Postgresql Database Server.

It allows a .Net client application (Console, WinForms, ASP.NET, Web Services...) to use a PostgreSQL server to send and receive data. It is developed using the guidelines specified in the .Net docs.

## 2. Npgsql Usage

This section explains Npgsql usage in a .Net Application. If you are used to developing Data Access applications using the Sql Server, OleDB or ODBC.NET providers, using Npgsql is very similar.

In order to use Npgsql, server must be listening to TCP/IP connections. TCP connections are enabled by default on 8.0 servers. 7.3 and below, should have postmaster started with -i option. Check Postgresql Documentation for details: http://www.postgresql.org/docs/7.4/static/postmaster-start.html

Note: Npgsql is still under development. Only features currently supported will be demonstrated. As Npgsql matures, more functionality will be available to be used.

### Adding required namespaces to your source file

First, to use Npgsql objects more easily, you have to tell the compiler to use the Npgsql namespace. It will also be needed to use the System.Data namespace as a lot of classes used for data manipulation reside in it. To do that, in C#, you use the using directive:

    using System.Data;
    using Npgsql;

### Establishing a connection

To establish a connection to a server located at ip 127.0.0.1, port 5432, as the user joe, with the password secret, using the database joedata, you use the NpgsqlConnection as:

    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();
      }
    }

### Connection String parameters

When establishing a connection, NpgsqlConnection accepts many parameters which can be used to modify its behavior. Here is the list of current parameters you can tweak: (From NpgsqlConnection source)

     Gets or sets the string used to connect to a PostgreSQL database.
            /// Valid values are:
            /// Server:                     Address/Name of Postgresql Server;
            /// Port:                       Port to connect to;
            /// Protocol:                   Protocol version to use, instead of automatic; Integer 2 or 3;
            /// Database:                   Database name. Defaults to user name if not specified;
            /// User Id:                    User name;
            /// Password:                   Password for clear text authentication;
            /// SSL:                        True or False. Controls whether to attempt a secure connection. Default = False;
            /// Pooling:                    True or False. Controls whether connection pooling is used. Default = True;
            /// MinPoolSize:                Min size of connection pool;
            /// MaxPoolSize:                Max size of connection pool;
            /// Encoding:                   Encoding to be used;
            /// Timeout:                    Time to wait for connection open in seconds.
            /// Sslmode:                    Mode for ssl connection control.

            Encoding can the ASCII or UNICODE. If your application uses characters with accents and with default settings it doesn't work, try changing that.
            Min pool size when specified will make NpgsqlConnection pre allocates this number of connections with the server.
            Sslmode can be one of the following values:
                Prefer - If it is possible to connect using ssl, it will be used.
                Require - If an ssl connection cannot be made, an exception is thrown.
                Allow - Not supported yet, just connects without ssl.
                Disable - No ssl connection is done.
                Default is Disable.

### Using NpgsqlCommand to add a row in a table

The previous example doesn't do anything useful. It only connects to the database and disconnects. If there is an error, a NpgsqlException is thrown. Now, suppose there is a table called table1 with two fields a and b both of type int. If you want to add the tuple (1, 1) in this table you could send the insert statement as follows:

    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();
        }
      }
    }

### Getting a single result using NpgsqlCommand.ExecuteScalar() method

To execute statements which return just one value you use the ExecuteScalar() method of the Command object:

    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();
        }
      }
    }

Other queries could also be used, for example "select count(*) from table1". Also, queries that don't return single values could be used, but only the first column of the first row would be returned.

### Getting full results from a query using NpgsqlCommand.ExecuteReader() method and NpgsqlDataReader object

To execute statements which return full results from a query you use the ExecuteReader() method of the NpgsqlCommand object:

    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();
        }
      }
    }

This code assumes there is a table called tablea in the database.

### Using parameters in a query

You can also send a parameterized query to the server using NpgsqlParamenter and NpgsqlParamenterCollection objects. A parameter is a string prefixed by : in the query string. The example below uses a parameter called 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();

        // Declare the parameter in the query string
        NpgsqlCommand command = new NpgsqlCommand("select * from tablea where column1 = :column1", conn);

        // Now add the parameter to the parameter collection of the command specifying its type.
        command.Parameters.Add(new NpgsqlParameter("column1", DbType.Int32));

        // Now, add a value to it and later execute the command as usual.
        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();
        }
      }
    }

This code assumes a table called tablea with at least a column named column1 of type int4.

### Using prepared statements

The previous example can also be used to send prepared statements request to server. This way, the query plan is create just once and reused by subsequent calls. Note that this feature is only available in server 7.3+ versions. If you call it in a server which doesn't support it, Npgsql will silently ignore it. This is good as you can create code which calls it but it will only have effect when connected to the supported servers. To do it, you just call the Prepare() method of the command.

    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();

        // Declare the parameter in the query string
        NpgsqlCommand command = new NpgsqlCommand("select * from tablea where column1 = :column1", conn);

        // Now add the parameter to the parameter collection of the command specifying its type.
        command.Parameters.Add(new NpgsqlParameter("column1", DbType.Int32);

        // Now, prepare the statement.
        command.Prepare();

        // Now, add a value to it and later execute the command as usual.
        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();
        }
      }
    }

This code assumes a table called tablea with at least a column named column1 of type int4.

### Using output parameters in a query

Output parameters can be used with Npgsql. Note that Npgsql "simulates" output parameter by parsing the first result set from the execution of a query and translating it to output parameters value. This can be done in two ways: mapped or not. A mapped parsing, tries to match the column name returned by resultset into a parameter with the same name. If a match is found, only the output parameters which has a match will be updated. If a map is not found, the output parameters are updated based on the order they were added to command parameters collection. This mapping is automatic. When parsing resultset, Npgsql tries to find a match. Both Output and InputOutput parameter directions are supported.

    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();

            // Send a query to backend.
            NpgsqlCommand command = new NpgsqlCommand("select * from tablea where column1 = 2", conn);

            // Now declare an output parameter to receive the first column of the tablea.

            NpgsqlParameter firstColumn = new NpgsqlParameter("firstcolumn", NpgsqlDbType.Integer);
            firstColumn.Direction = ParameterDirection.Output;

            command.Parameters.Add(firstColumn);

            try
            {
                command.ExecuteNonQuery();

                // Now, the firstcolumn parameter will have the value of the first column of the resultset.
                Console.WriteLine(firstColumn.Value);

            }

            finally
            {
                conn.Close();
            }
        }
    }

### Function calling

To call a function, you just set the CommandType property of the NpgsqlCommand object to CommandType.StoredProcedure and pass the name of the function you want to call as the query string.

    using System;
    using System.Data;
    using Npgsql;

    // This example uses a function called funcC() with the following definition:
    // create function funcC() returns int8 as '
    // select count(*) from tablea;
    // ' language 'sql';

    // Note that the return type of select count(*) changed from int4 to int8 in 7.3+ versions. To use this function
    // in a 7.2 server, change the return type from int8 to 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();
        }
      }
    }

In the same way as clear queries, you can specify parameters to function calls.

    using System;
    using System.Data;
    using Npgsql;

    // This example uses a function called funcC() with the following definition:
    // 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();
        }
      }
    }

This code assumes a table called tablea with at least a field called field_int4 of type int4.

### Working with Datasets

You can use Npgsql when working with Datasets. This allows you to do changes in the dataset and have them propagated back to backend. The below example shows how to add a row using the Dataset:

    // This method expects the following table in the backend:
    //
    //	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();
    }

### Working with strong typed datasets

This example will show how to use a strong typed dataset generated with xsd. To do so, we need a .xsd file specifing the schema to the strong dataset. You can generate this file by hand, or you can use xsd to generate it for you. To have xsd generate the .xsd for you, you have to suppy it with a .xml file which it will infer the .xsd from. We can use a .xml file generated with a DataAdapter.WriteXml() method:

    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");
    }

This will give us a file which looks similar to this:

    <?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>

This file will be used with xsd to generate the .xsd file with the following command:

    xsd StrongDataSetFeed.xml

xsd will produce an xml schema which will have all types specified as string, we just change the xsd to use the correct types and have a .xsd file similar to this:

    <?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>

With this file we issue the following command to have xsd generate the strong dataset:

    xsd StrongDataSetFeed.xsd /dataset

Which will generate a file we can compile to get an assembly with the strong dataset. To use it, we do the following:

    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);
    		}
    	}
    }

### Working with binary data and bytea datatype

This sample takes a filename as argument, inserts its contents to a table called tableByteA which contains a field called field_bytea of type bytea and a field called field_serial of type serial. Later gets its contents and write a new file with the sufix "database" in its end.

table schema: 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();

    	}
    }

### Working with large object support

This sample is the same as the bytea code support above. The difference is that we will use the large object support of Postgresql. This sample stores the file in postgresql and later removes it. As bytea sample, it writes a file with a "database" suffix.

    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();

        }
    }

Another example, contributed by Mirek (mirek at mascort dot com dot pl), uses the large object support to get an image from database and shows it in a form.

    using System;
    using Npgsql;
    using NpgsqlTypes;
    using System.Drawing;
    using System.IO;

    //metod whos take picture oid  from database

    public int takeOID(int id)

    {

        //it's a metod whos connect  to database and return picture 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;

    }

    //take a picture from database and convert to Image type

    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;

    }

    //next I just use this metod

    pictureBox1.Image = Image pobierzRysunek(1);

### 2.1 Npgsql.dll file location

In order for the .Net Runtime to locate the Npgsql.dll library, this file must be put in the same directory the application is, unless you specify another directory as a path to private components through a configuration file (using the probing element). Please, see the .Net docs for information on how the runtime probes (locates) assemblies to be loaded. There is also a section called "Path to Private Components"

In ASP.NET and Web Services .Net Applications, there must be a directory called "bin" below the ASP.NET root application directory. So, for example the application directory is called "ASPNETApplication", Npgsql.dll must be placed in the "ASPNETApplication\bin" directory. If it's not, you will get a lot of compiling errors when trying to use Npgsql.

You can also put the Npgsql assembly in the Global Cache Assembly. Since 0.4 version, Npgsql is strongly signed which means you can use gacutil to install it. Issue the following command to do it:

    gacutil -i Npgsql.dll

Please, refer to "Installing an Assembly in the Global Cache Assembly" section of MSDN docs for more help.

### 2.2 Using Npgsql Logging support

Sometimes it is necessary to trace Npgsql's behaviour to track errors. Npgsql can log messages to a specified file or to the console or both.

There are three levels of logging:

- None
- Normal
- Debug

The following NpgsqlEventLog static properties may also be used:

- Level - Can be one of the LogLevel enum values: None, Normal, Debug.
- LogName - Full path of the file where to log into.
- EchoMessages - Log to the console.

The example below shows how to log to the console and a file using the level Debug:

    using System.Data;
    using Npgsql;

    public static class NpgsqlUserManual
    {
      public static void Main(String[] args)
      {
        // Enable logging.
        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();
      }
    }

Running this code gives the following output:

    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()

I used the Debug level to show that a lot of information can be obtained. Of course, using the Normal level would be less verbose. Also, this same information was added to the file NpgsqlTests.LogFile.

### 2.3 Npgsql design time support

Npgsql 0.6 and higher provide initial design time support. This means that you can drag and drop a NpgsqlConnection in the Form-Designer of Visual Studio .NET as you are used to with SqlConnections or OleDbConnections.
There is also a Dialog to edit and validate the ConnectionString

To do so you must:

1. Install Npgsql.dll into the gac
2. Add a new Registry-Key below 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders' and set it's default value to the path of your Npgsql.dll
3. Open Visual Studio .NET
4. Right-click the "Data"-Tab of the Toolbox
5. Click add/remove element
6. On the .Net-Tab select NpgsqlConnection

As result you will have an icon named NpgsqlConnection in the Data-Tab of the Toolbox

## 3. Current Npgsql Status

### Supported data types

Npgsql supports the following data types:

Postgresql Type | NpgsqlDbType | System.DbType Enum | .Net System Type
int8 | Real | 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, timestamptz | Timestamp | DateTime | Decimal
varchar | Varchar | String | String

### Features

- You can send select, insert, delete queries
- You can call functions
- You can get resultset from functions
- You can use parameters in your queries. Input, Output and InputOuput parameters are supported
- Parameter names have ":" markers or "@" markers to easy migration of code. :parameter -or- @parameter
- Support for transactions