| /* |
| Copyright 2016 The Transicator Authors |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| package pgclient |
| |
| import ( |
| "errors" |
| "fmt" |
| |
| log "github.com/Sirupsen/logrus" |
| ) |
| |
| /* |
| A ColumnInfo describes a single row in a query result. |
| */ |
| type ColumnInfo struct { |
| // Name of the column |
| Name string |
| // Postgres type OID |
| Type PgType |
| // Was the column represented in binary form in the result row? |
| Binary bool |
| } |
| |
| /* |
| SimpleQuery executes a query as a string, and returns a list of rows. |
| It does not do any kind of preparation. The first parameter returned is an |
| array of descriptors for each row. The second is an array of rows. |
| */ |
| func (c *PgConnection) SimpleQuery(query string) ([]ColumnInfo, [][]string, error) { |
| cols, rawRows, _, err := c.exec(query) |
| var rows [][]string |
| if err == nil { |
| // Convert rows into an array of strings |
| for _, rawRow := range rawRows { |
| var cols []string |
| for _, rawCol := range rawRow { |
| cols = append(cols, string(rawCol)) |
| } |
| rows = append(rows, cols) |
| } |
| } |
| return cols, rows, err |
| } |
| |
| /* |
| SimpleExec executes a query as a string, and returns a row count. |
| It does not do any kind of preparation. The first parameter returned is an |
| array of descriptors for each row. The second is an array of rows. |
| */ |
| func (c *PgConnection) SimpleExec(query string) (int64, error) { |
| _, _, rowCount, err := c.exec(query) |
| return rowCount, err |
| } |
| |
| func (c *PgConnection) exec(query string) ([]ColumnInfo, [][][]byte, int64, error) { |
| log.Debugf("Query: %s", query) |
| qm := NewOutputMessage(Query) |
| qm.WriteString(query) |
| err := c.WriteMessage(qm) |
| if err != nil { |
| return nil, nil, 0, err |
| } |
| |
| var rowDesc []ColumnInfo |
| var rows [][][]byte |
| var rowCount int64 |
| var cmdErr error |
| |
| // Loop until we get a ReadyForQuery message, or until we get an error |
| // reading messages at all. |
| for { |
| im, err := c.readStandardMessage() |
| if err != nil { |
| return nil, nil, 0, err |
| } |
| |
| switch im.Type() { |
| case CommandComplete: |
| // Command complete. Could return what we did. |
| rowCount, err = ParseCommandComplete(im) |
| case CopyInResponse, CopyOutResponse: |
| // Copy in/out response -- not yet supported |
| cmdErr = errors.New("COPY operations not supported by this client") |
| case RowDescription: |
| rowDesc, err = ParseRowDescription(im) |
| if err != nil { |
| cmdErr = err |
| } |
| case DataRow: |
| row, err := ParseDataRow(im) |
| if err != nil { |
| cmdErr = err |
| } else { |
| rows = append(rows, row) |
| } |
| case EmptyQueryResponse: |
| // Empty query response. Nothing to do really. |
| case ReadyForQuery: |
| return rowDesc, rows, rowCount, cmdErr |
| case ErrorResponse: |
| // Need to record error and keep reading until we get ReadyForQuery |
| cmdErr = ParseError(im) |
| default: |
| cmdErr = fmt.Errorf("Invalid server response %s", im.Type()) |
| } |
| } |
| } |