From 1d1d836207eec4cb78ad23a8edee3769d78e67df Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Mon, 15 Jul 2013 08:14:32 -0500 Subject: [PATCH] Added more docs --- connection.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++ connection_pool.go | 18 ++++++++++------- data_row_reader.go | 2 ++ sanitize.go | 7 +++++++ 4 files changed, 68 insertions(+), 7 deletions(-) diff --git a/connection.go b/connection.go index b589d9dd..976c4852 100644 --- a/connection.go +++ b/connection.go @@ -131,6 +131,15 @@ func (c *Connection) Close() (err error) { return c.txMsg('X', c.getBuf()) } +// SelectFunc executes sql and for each row returned calls onDataRow. 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. +// +// SelectFunc calls onDataRow as the rows are received. This means that it does not +// need to simultaneously store the entire result set in memory. It also means that +// it is possible to process some rows and then for an error to occur. Callers +// should be aware of this possibility. func (c *Connection) SelectFunc(sql string, onDataRow func(*DataRowReader) error, arguments ...interface{}) (err error) { var fields []FieldDescription @@ -169,6 +178,10 @@ func (c *Connection) SelectFunc(sql string, onDataRow func(*DataRowReader) error } } +// SelectRows executes sql and returns a slice of maps representing the found rows. +// 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. func (c *Connection) SelectRows(sql string, arguments ...interface{}) (rows []map[string]interface{}, err error) { rows = make([]map[string]interface{}, 0, 8) onDataRow := func(r *DataRowReader) error { @@ -179,6 +192,11 @@ func (c *Connection) SelectRows(sql string, arguments ...interface{}) (rows []ma return } +// SelectRow executes sql and returns a map representing the found row. +// 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. +// // Returns a NotSingleRowError if exactly one row is not found func (c *Connection) SelectRow(sql string, arguments ...interface{}) (row map[string]interface{}, err error) { var numRowsFound int64 @@ -195,6 +213,11 @@ func (c *Connection) SelectRow(sql string, arguments ...interface{}) (row map[st return } +// SelectValue executes sql and returns a single value. 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. +// // Returns a UnexpectedColumnCountError if exactly one column is not found // Returns a NotSingleRowError if exactly one row is not found func (c *Connection) SelectValue(sql string, arguments ...interface{}) (v interface{}, err error) { @@ -218,6 +241,11 @@ func (c *Connection) SelectValue(sql string, arguments ...interface{}) (v interf return } +// SelectValues executes sql and returns a slice of values. 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. +// // Returns a UnexpectedColumnCountError if exactly one column is not found func (c *Connection) SelectValues(sql string, arguments ...interface{}) (values []interface{}, err error) { values = make([]interface{}, 0, 8) @@ -233,6 +261,8 @@ func (c *Connection) SelectValues(sql string, arguments ...interface{}) (values return } +// Prepare creates a prepared statement with name and sql. sql can contain placeholders +// for bound parameters. These placeholders are referenced positional as $1, $2, etc. func (c *Connection) Prepare(name, sql string) (err error) { // parse buf := c.getBuf() @@ -299,6 +329,7 @@ func (c *Connection) Prepare(name, sql string) (err error) { } } +// Deallocate released a prepared statement func (c *Connection) Deallocate(name string) (err error) { delete(c.preparedStatements, name) _, err = c.Execute("deallocate " + c.QuoteIdentifier(name)) @@ -403,6 +434,9 @@ func (c *Connection) sendPreparedQuery(ps *preparedStatement, arguments ...inter } +// Execute 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. func (c *Connection) Execute(sql string, arguments ...interface{}) (commandTag string, err error) { if err = c.sendQuery(sql, arguments...); err != nil { return @@ -430,10 +464,24 @@ func (c *Connection) Execute(sql string, arguments ...interface{}) (commandTag s } } +// Transaction runs f in a transaction. f should return true if the transaction +// should be committed or false if it should be rolled back. Return value committed +// is if the transaction was committed or not. committed should be checked separately +// from err as an explicit rollback is not an error. Transaction will use the default +// isolation level for the current connection. To use a specific isolation level see +// TransactionIso func (c *Connection) Transaction(f func() bool) (committed bool, err error) { return c.transaction("", f) } +// TransactionIso is the same as Transaction except it takes an isoLevel argument that +// it uses as the transaction isolation level. +// +// Valid isolation levels are: +// serializable +// repeatable read +// read committed +// read uncommitted func (c *Connection) TransactionIso(isoLevel string, f func() bool) (committed bool, err error) { return c.transaction(isoLevel, f) } diff --git a/connection_pool.go b/connection_pool.go index ee3eb07d..a8b66717 100644 --- a/connection_pool.go +++ b/connection_pool.go @@ -6,8 +6,9 @@ type ConnectionPool struct { MaxConnections int } -// options: options used by Connect -// MaxConnections: max simultaneous connections to use (currently all are immediately connected) +// NewConnectionPool creates a new ConnectionPool. options are passed through to +// Connect directly. MaxConnections is max simultaneous connections to use +// (currently all are immediately connected). func NewConnectionPool(parameters ConnectionParameters, MaxConnections int) (p *ConnectionPool, err error) { p = new(ConnectionPool) p.connectionChannel = make(chan *Connection, MaxConnections) @@ -27,11 +28,13 @@ func NewConnectionPool(parameters ConnectionParameters, MaxConnections int) (p * return } +// Acquire takes exclusive use of a connection until it is released. func (p *ConnectionPool) Acquire() (c *Connection) { c = <-p.connectionChannel return } +// Release gives up use of a connection. func (p *ConnectionPool) Release(c *Connection) { if c.txStatus != 'I' { c.Execute("rollback") @@ -39,6 +42,7 @@ func (p *ConnectionPool) Release(c *Connection) { p.connectionChannel <- c } +// Close ends the use of a connection by closing all underlying connections. func (p *ConnectionPool) Close() { for i := 0; i < p.MaxConnections; i++ { c := <-p.connectionChannel @@ -46,7 +50,7 @@ func (p *ConnectionPool) Close() { } } -// Acquires a connection, delegates the call to that connection, and releases the connection +// SelectFunc acquires a connection, delegates the call to that connection, and releases the connection func (p *ConnectionPool) SelectFunc(sql string, onDataRow func(*DataRowReader) error, arguments ...interface{}) (err error) { c := p.Acquire() defer p.Release(c) @@ -54,7 +58,7 @@ func (p *ConnectionPool) SelectFunc(sql string, onDataRow func(*DataRowReader) e return c.SelectFunc(sql, onDataRow, arguments...) } -// Acquires a connection, delegates the call to that connection, and releases the connection +// SelectRows acquires a connection, delegates the call to that connection, and releases the connection func (p *ConnectionPool) SelectRows(sql string, arguments ...interface{}) (rows []map[string]interface{}, err error) { c := p.Acquire() defer p.Release(c) @@ -62,7 +66,7 @@ func (p *ConnectionPool) SelectRows(sql string, arguments ...interface{}) (rows return c.SelectRows(sql, arguments...) } -// Acquires a connection, delegates the call to that connection, and releases the connection +// SelectRow acquires a connection, delegates the call to that connection, and releases the connection func (p *ConnectionPool) SelectRow(sql string, arguments ...interface{}) (row map[string]interface{}, err error) { c := p.Acquire() defer p.Release(c) @@ -70,7 +74,7 @@ func (p *ConnectionPool) SelectRow(sql string, arguments ...interface{}) (row ma return c.SelectRow(sql, arguments...) } -// Acquires a connection, delegates the call to that connection, and releases the connection +// SelectValue acquires a connection, delegates the call to that connection, and releases the connection func (p *ConnectionPool) SelectValue(sql string, arguments ...interface{}) (v interface{}, err error) { c := p.Acquire() defer p.Release(c) @@ -78,7 +82,7 @@ func (p *ConnectionPool) SelectValue(sql string, arguments ...interface{}) (v in return c.SelectValue(sql, arguments...) } -// Acquires a connection, delegates the call to that connection, and releases the connection +// SelectValues acquires a connection, delegates the call to that connection, and releases the connection func (p *ConnectionPool) SelectValues(sql string, arguments ...interface{}) (values []interface{}, err error) { c := p.Acquire() defer p.Release(c) diff --git a/data_row_reader.go b/data_row_reader.go index 80d73292..6684177d 100644 --- a/data_row_reader.go +++ b/data_row_reader.go @@ -1,5 +1,6 @@ package pgx +// DataRowReader is used by SelectFunc to process incoming rows. type DataRowReader struct { mr *MessageReader fields []FieldDescription @@ -19,6 +20,7 @@ func newDataRowReader(mr *MessageReader, fields []FieldDescription) (r *DataRowR return } +// ReadValue returns the next value from the current row. func (r *DataRowReader) ReadValue() interface{} { fieldDescription := r.fields[r.currentFieldIdx] r.currentFieldIdx++ diff --git a/sanitize.go b/sanitize.go index 25419e97..d774be17 100644 --- a/sanitize.go +++ b/sanitize.go @@ -10,16 +10,23 @@ import ( var literalPattern *regexp.Regexp = regexp.MustCompile(`\$\d+`) +// QuoteString escapes and quotes a string making it safe for interpolation +// into an SQL string. func (c *Connection) QuoteString(input string) (output string) { output = "'" + strings.Replace(input, "'", "''", -1) + "'" return } +// QuoteIdentifier escapes and quotes an identifier making it safe for +// interpolation into an SQL string func (c *Connection) QuoteIdentifier(input string) (output string) { output = `"` + strings.Replace(input, `"`, `""`, -1) + `"` return } +// SanitizeSql substitutely args positionaly into sql. Placeholder values are +// $ prefixed integers like $1, $2, $3, etc. args are sanitized and quoted as +// appropriate. func (c *Connection) SanitizeSql(sql string, args ...interface{}) (output string) { replacer := func(match string) (replacement string) { n, _ := strconv.ParseInt(match[1:], 10, 0)