diff --git a/README.md b/README.md index 5add54d2..664333c6 100644 --- a/README.md +++ b/README.md @@ -4,165 +4,41 @@ PostgreSQL client library for Go ## Description -pgx is a database connection library designed specifically for PostgreSQL. pgx offers an interface similar to database/sql that offers more performance and features than are available the database/sql interface. It also can run as a database/sql compatible driver by importing github.com/jackc/pgx/stdlib. +pgx is a database connection library designed specifically for PostgreSQL. pgx +offers an interface similar to database/sql that offers more performance and +features than are available with the database/sql interface. It also can run as +a database/sql compatible driver. -## Features +## Native Interface -Below are some of the standout features of pgx. +The pgx native interface is faster than using pgx as a driver for database/sql. +The performance improvement ranges from as little as 3% for returning a single +value to 30% for returning many rows with multiple columns. -### Familiar Query Interface +The pgx native interface supports the following extra features: -pgx implements Query, QueryRow, and Scan in the familiar database/sql style. +* Listen / notify +* Transaction isolation level control +* Full TLS connection control +* Binary format support for custom types (can be much faster) +* Logging support +* Configurable connection pool with after connect hooks to do arbitrary connection setup +* PostgreSQL array to Go slice mapping for integers, floats, and strings -```go -var name string -var weight int64 -err := conn.QueryRow("select name, weight from widgets where id=$1", 42).Scan(&name, &weight) -if err != nil { - return err -} -``` +## database/sql -pgx adds convenience to Query in that it is only necessary to call Close if you -want to ignore the rest of the rows. When Next has read all rows or an error -occurs, the rows are closed automatically. +Import the ```github.com/jackc/pgx/stdlib``` package to use pgx as a driver for +database/sql. It is possible to retrieve a pgx connection from database/sql on +demand. This allows using the database/sql interface in most places, but using +pgx directly when more performance or PostgreSQL specific features are needed. -```go -var sum int32 +## Documentation -rows, err := conn.Query("select generate_series(1,$1)", 10) -if err != nil { - t.Fatalf("conn.Query failed: ", err) -} - -for rows.Next() { - var n int32 - rows.Scan(&n) - sum += n -} - -// rows.Close implicitly called when rows.Next is finished - -if rows.Err() != nil { - t.Fatalf("conn.Query failed: ", err) -} - -// ... -``` - -### Prepared Statements - -Prepared statements are easy to use in pgx. Just call Prepare with the name of -the statement and the SQL. To execute a prepared statement just pass the name -of the statement into a Query, QueryRow, or Exec as the SQL text. It will -automatically detect that it is the name of a prepared statement and execute -it. - -```go -if _, err := conn.Prepare("getTime", "select now()"); err == nil { - // handle err -} - -var t time.Time -err := conn.QueryRow("getTime").Scan(&t) -if err != nil { - return err -} -``` - -### Explicit Connection Pool - -Connection pool usage is explicit and configurable. In pgx, a connection can -be created and managed directly, or a connection pool with a configurable -maximum connections can be used. Also, the connection pool offers an after -connect hook that allows every connection to be automatically setup before -being made available in the connection pool. This is especially useful to -ensure all connections have the same prepared statements available or to -change any other connection settings. - -It delegates Query, QueryRow, Exec, and Begin functions to an automatically -checked out and released connection so you can avoid manually acquiring and -releasing connections when you do not need that level of control. - -```go -var name string -var weight int64 -err := pool.QueryRow("select name, weight from widgets where id=$1", 42).Scan(&name, &weight) -if err != nil { - return err -} -``` - -### Transactions - -Transactions are started by calling Begin or BeginIso. The BeginIso variant -creates a transaction with a specified isolation level. - -```go - tx, err := conn.Begin() - if err != nil { - t.Fatalf("conn.Begin failed: %v", err) - } - - _, err = tx.Exec("insert into foo(id) values (1)") - if err != nil { - t.Fatalf("tx.Exec failed: %v", err) - } - - err = tx.Commit() - if err != nil { - t.Fatalf("tx.Commit failed: %v", err) - } -}) -``` - -### Listen / Notify - -Pgx can listen to the PostgreSQL notification system with the -WaitForNotification function. It takes a maximum time to wait for a -notification. - -```go -if notification, err := conn.WaitForNotification(time.Second); err != nil { - // do something with notification -} -``` - -### TLS - -The pgx ConnConfig struct has a TLSConfig field. If this field is -nil, then TLS will be disabled. If it is present, then it will be used to -configure the TLS connection. - -### Custom Type Support - -pgx includes support for the common data types like integers, floats, strings, -dates, and times that have direct mappings between Go and SQL. Support can be -added for additional types like point, hstore, numeric, etc. that do not have -direct mappings in Go. See the documentation for more information. - -### Null Mapping - -pgx includes Null* types in a similar fashion to database/sql that implement the -necessary interfaces to be encoded and scanned. - -### Array Mapping - -pgx maps between int16, int32, int64, float32, float64, and string Go slices -and the equivalent PostgreSQL array type. Go slices of native types do not -support nulls, so if a PostgreSQL array that contains a slice is read into a -native Go slice an error will occur. - -### Logging - -pgx defines a simple logger interface. Connections optionally accept a logger -that satisfies this interface. The [log15 -package](http://gopkg.in/inconshreveable/log15.v2) satisfies this interface -and it is simple to define adapters for other loggers. +pgx includes extensive documentation in the godoc format. It is viewable online at [godoc.org](https://godoc.org/github.com/jackc/pgx). ## Testing -Pgx supports multiple connection and authentication types. Setting up a test +pgx supports multiple connection and authentication types. Setting up a test environment that can test all of them can be cumbersome. In particular, Windows cannot test Unix domain socket connections. Because of this pgx will skip tests for connection types that are not configured. @@ -204,3 +80,10 @@ If you are developing on Windows with TCP connections: host pgx_test pgx_none 127.0.0.1/32 trust host pgx_test pgx_pw 127.0.0.1/32 password host pgx_test pgx_md5 127.0.0.1/32 md5 + +## Version Policy + +pgx follows semantic versioning for the documented public API. ```master``` +branch tracks the latest stable branch (```v2```). Consider using ```import +"gopkg.in/jackc/pgx.v2"``` to lock to the ```v2``` branch or use a vendoring +tool such as [godep](https://github.com/tools/godep). diff --git a/conn.go b/conn.go index 53f84c75..4c516167 100644 --- a/conn.go +++ b/conn.go @@ -591,8 +591,7 @@ func (c *Conn) sendPreparedQuery(ps *PreparedStatement, arguments ...interface{} } // Exec executes sql. sql can be either a prepared statement name or an SQL string. -// arguments will be sanitized before being interpolated into sql strings. arguments -// should be referenced positionally from the sql string as $1, $2, etc. +// arguments should be referenced positionally from the sql string as $1, $2, etc. func (c *Conn) Exec(sql string, arguments ...interface{}) (commandTag CommandTag, err error) { startTime := time.Now() diff --git a/doc.go b/doc.go index a63485d4..db0e0ca2 100644 --- a/doc.go +++ b/doc.go @@ -5,6 +5,132 @@ It remains as similar to the database/sql interface as possible while providing better speed and access to PostgreSQL specific features. Import github.com/jack/pgx/stdlib to use pgx as a database/sql compatible driver. +Query Interface + +pgx implements Query and Scan in the familiar database/sql style. + + var sum int32 + + // Send the query to the server. The returned rows MUST be closed + // before conn can be used again. + rows, err := conn.Query("select generate_series(1,$1)", 10) + if err != nil { + return err + } + + // rows.Close is called by rows.Next when all rows are read + // or an error occurs in Next or Scan. So it may optionally be + // omitted if nothing in the rows.Next loop can panic. It is + // safe to close rows multiple times. + defer rows.Close() + + // Iterate through the result set + for rows.Next() { + var n int32 + err = rows.Scan(&n) + if err != nil { + return err + } + sum += n + } + + // Any errors encountered by rows.Next or rows.Scan will be returned here + if rows.Err() != nil { + return err + } + + // No errors found - do something with sum + +pgx also implements QueryRow in the same style as database/sql. + + var name string + var weight int64 + err := conn.QueryRow("select name, weight from widgets where id=$1", 42).Scan(&name, &weight) + if err != nil { + return err + } + +Use exec to execute a query that does not return a result set. + + commandTag, err := conn.Exec("delete from widgets where id=$1", 42) + if err != nil { + return err + } + if commandTag.RowsAffected() != 1 { + return errors.New("No row found to delete") + } + +Connection Pool + +Connection pool usage is explicit and configurable. In pgx, a connection can +be created and managed directly, or a connection pool with a configurable +maximum connections can be used. Also, the connection pool offers an after +connect hook that allows every connection to be automatically setup before +being made available in the connection pool. This is especially useful to +ensure all connections have the same prepared statements available or to +change any other connection settings. + +It delegates Query, QueryRow, Exec, and Begin functions to an automatically +checked out and released connection so you can avoid manually acquiring and +releasing connections when you do not need that level of control. + + var name string + var weight int64 + err := pool.QueryRow("select name, weight from widgets where id=$1", 42).Scan(&name, &weight) + if err != nil { + return err + } + +Transactions + +Transactions are started by calling Begin or BeginIso. The BeginIso variant +creates a transaction with a specified isolation level. + + tx, err := conn.Begin() + if err != nil { + return err + } + // Rollback is safe to call even if the tx is already closed, so if + // the tx commits successfully, this is a no-op + defer tx.Rollback() + + _, err = tx.Exec("insert into foo(id) values (1)") + if err != nil { + return err + } + + err = tx.Commit() + if err != nil { + return err + } + +Listen and Notify + +pgx can listen to the PostgreSQL notification system with the +WaitForNotification function. It takes a maximum time to wait for a +notification. + + err := conn.Listen("channelname") + if err != nil { + return nil + } + + if notification, err := conn.WaitForNotification(time.Second); err != nil { + // do something with notification + } + +Null Mapping + +pgx includes Null* types in a similar fashion to database/sql that implement the +necessary interfaces to be encoded and scanned. + +Array Mapping + +pgx maps between int16, int32, int64, float32, float64, and string Go slices +and the equivalent PostgreSQL array type. Go slices of native types do not +support nulls, so if a PostgreSQL array that contains a slice is read into a +native Go slice an error will occur. + Custom Type Support pgx includes support for the common data types like integers, floats, strings, @@ -19,7 +145,7 @@ However, that is impossible as the query has already been sent by the time the Scanner is invoked. The solution to this is the global DefaultTypeFormats. If a custom type prefers binary format it should register it there. - pgx.DefaultTypeFormats["point"] = pgx.BinaryFormatCode + pgx.DefaultTypeFormats["point"] = pgx.BinaryFormatCode Note that the type is referred to by name, not by OID. This is because custom PostgreSQL types like hstore will have different OIDs on different servers. When @@ -29,5 +155,19 @@ Conn.PgTypes. See example_custom_type_test.go for an example of a custom type for the PostgreSQL point type. + +TLS + +The pgx ConnConfig struct has a TLSConfig field. If this field is +nil, then TLS will be disabled. If it is present, then it will be used to +configure the TLS connection. This allows total configuration of the TLS +connection. + +Logging + +pgx defines a simple logger interface. Connections optionally accept a logger +that satisfies this interface. The log15 package +(http://gopkg.in/inconshreveable/log15.v2) satisfies this interface +and it is simple to define adapters for other loggers. */ package pgx diff --git a/query.go b/query.go index d1e8b1cd..97af8719 100644 --- a/query.go +++ b/query.go @@ -103,10 +103,8 @@ func (rows *Rows) readUntilReadyForQuery() { } } -// Close closes the rows, making the connection ready for use again. It is not -// usually necessary to call Close explicitly because reading all returned rows -// with Next automatically closes Rows. It is safe to call Close after rows is -// already closed. +// Close closes the rows, making the connection ready for use again. It is safe +// to call Close after rows is already closed. func (rows *Rows) Close() { if rows.closed { return