Postgres Data Source (#9475)

* add postgresql datasource

* add rest of files for postgres datasource

* fix timeseries query, remove unused code

* consistent naming, refactoring

* s/mysql/postgres/

* s/mysql/postgres/

* couple more tests

* tests for more datatypes

* fix macros for postgres

* add __timeSec macro

* add frontend for postgres datasource

* adjust documentation

* fix formatting

* add proper plugin description

* merge editor changes from mysql

* port changes from mysql datasource

* set proper defaultQuery for postgres

* add time_sec to timeseries query
accept int for value for timeseries query

* revert allowing time_sec and handle int or float values as unix
timestamp for "time" column

* fix tslint error

* handle decimal values in timeseries query

* allow setting sslmode for postgres datasource

* use type switch for handling data types

* fix value for timeseries query

* refactor timeseries queries to make them more flexible

* remove debug statement from inner loop in type conversion

* use plain for loop in getTypedRowData

* fix timeseries queries

* adjust postgres datasource to tsdb refactoring

* adjust postgres datasource to frontend changes

* update lib/pq to latest version

* move type conversion to getTypedRowData

* handle address types cidr, inet and macaddr

* adjust response parser and docs for annotations

* convert unknown types to string

* add documentation for postgres datasource

* add another example query with metric column

* set more helpful default query

* update help text in query editor

* handle NULL in value column of timeseries query

* add __timeGroup macro

* add test for __timeGroup macro

* document __timeGroup and set proper default query for annotations

* fix typos in docs

* add postgres to list of datasources

* add postgres to builtInPlugins

* mysql: refactoring as prep for merging postgres

Refactors out the initialization of the xorm engine and the query logic
for an sql data source.

* mysql: rename refactoring + test update

* postgres:refactor to use SqlEngine(same as mysql)

Refactored to use a common base class with the MySql data source.

Other changes from the original PR:
- Changed time column to be time_sec to allow other time units in the
future and to be the same as MySQL
- Changed integration test to test the main Query method rather than
the private transformToTable method
- Changed the __timeSec macro name to __timeEpoch
- Renamed PostgresExecutor to PostgresQueryEndpoint

Fixes #9209 (the original PR)

* postgres: encrypt password on config page

With some other cosmetic changes to the config page:
- placeholder texts
- reset button for the password after it has been encrypted.
- default value for the sslmode field.

* postgres: change back col name to time from time_sec

* postgres mysql: remove annotation title

Title has been removed from annotations

* postgres: fix images for docs page

* postgres mysql: fix specs
This commit is contained in:
Daniel Lee
2017-10-10 15:19:14 +02:00
committed by GitHub
parent 630e6f5da6
commit d1c9760fa8
36 changed files with 2231 additions and 478 deletions

6
vendor/github.com/lib/pq/array.go generated vendored
View File

@@ -13,7 +13,7 @@ import (
var typeByteSlice = reflect.TypeOf([]byte{})
var typeDriverValuer = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
var typeSqlScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
var typeSQLScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
// Array returns the optimal driver.Valuer and sql.Scanner for an array or
// slice of any dimension.
@@ -278,7 +278,7 @@ func (GenericArray) evaluateDestination(rt reflect.Type) (reflect.Type, func([]b
// TODO calculate the assign function for other types
// TODO repeat this section on the element type of arrays or slices (multidimensional)
{
if reflect.PtrTo(rt).Implements(typeSqlScanner) {
if reflect.PtrTo(rt).Implements(typeSQLScanner) {
// dest is always addressable because it is an element of a slice.
assign = func(src []byte, dest reflect.Value) (err error) {
ss := dest.Addr().Interface().(sql.Scanner)
@@ -587,7 +587,7 @@ func appendArrayElement(b []byte, rv reflect.Value) ([]byte, string, error) {
}
}
var del string = ","
var del = ","
var err error
var iv interface{} = rv.Interface()

117
vendor/github.com/lib/pq/conn.go generated vendored
View File

@@ -27,12 +27,12 @@ var (
ErrNotSupported = errors.New("pq: Unsupported command")
ErrInFailedTransaction = errors.New("pq: Could not complete operation in a failed transaction")
ErrSSLNotSupported = errors.New("pq: SSL is not enabled on the server")
ErrSSLKeyHasWorldPermissions = errors.New("pq: Private key file has group or world access. Permissions should be u=rw (0600) or less.")
ErrCouldNotDetectUsername = errors.New("pq: Could not detect default username. Please provide one explicitly.")
ErrSSLKeyHasWorldPermissions = errors.New("pq: Private key file has group or world access. Permissions should be u=rw (0600) or less")
ErrCouldNotDetectUsername = errors.New("pq: Could not detect default username. Please provide one explicitly")
errUnexpectedReady = errors.New("unexpected ReadyForQuery")
errNoRowsAffected = errors.New("no RowsAffected available after the empty statement")
errNoLastInsertId = errors.New("no LastInsertId available after the empty statement")
errNoLastInsertID = errors.New("no LastInsertId available after the empty statement")
)
type Driver struct{}
@@ -131,7 +131,7 @@ type conn struct {
}
// Handle driver-side settings in parsed connection string.
func (c *conn) handleDriverSettings(o values) (err error) {
func (cn *conn) handleDriverSettings(o values) (err error) {
boolSetting := func(key string, val *bool) error {
if value, ok := o[key]; ok {
if value == "yes" {
@@ -145,18 +145,18 @@ func (c *conn) handleDriverSettings(o values) (err error) {
return nil
}
err = boolSetting("disable_prepared_binary_result", &c.disablePreparedBinaryResult)
err = boolSetting("disable_prepared_binary_result", &cn.disablePreparedBinaryResult)
if err != nil {
return err
}
err = boolSetting("binary_parameters", &c.binaryParameters)
err = boolSetting("binary_parameters", &cn.binaryParameters)
if err != nil {
return err
}
return nil
}
func (c *conn) handlePgpass(o values) {
func (cn *conn) handlePgpass(o values) {
// if a password was supplied, do not process .pgpass
if _, ok := o["password"]; ok {
return
@@ -229,10 +229,10 @@ func (c *conn) handlePgpass(o values) {
}
}
func (c *conn) writeBuf(b byte) *writeBuf {
c.scratch[0] = b
func (cn *conn) writeBuf(b byte) *writeBuf {
cn.scratch[0] = b
return &writeBuf{
buf: c.scratch[:5],
buf: cn.scratch[:5],
pos: 1,
}
}
@@ -310,9 +310,8 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
u, err := userCurrent()
if err != nil {
return nil, err
} else {
o["user"] = u
}
o["user"] = u
}
cn := &conn{
@@ -698,7 +697,7 @@ var emptyRows noRows
var _ driver.Result = noRows{}
func (noRows) LastInsertId() (int64, error) {
return 0, errNoLastInsertId
return 0, errNoLastInsertID
}
func (noRows) RowsAffected() (int64, error) {
@@ -707,7 +706,7 @@ func (noRows) RowsAffected() (int64, error) {
// Decides which column formats to use for a prepared statement. The input is
// an array of type oids, one element per result column.
func decideColumnFormats(colTyps []oid.Oid, forceText bool) (colFmts []format, colFmtData []byte) {
func decideColumnFormats(colTyps []fieldDesc, forceText bool) (colFmts []format, colFmtData []byte) {
if len(colTyps) == 0 {
return nil, colFmtDataAllText
}
@@ -719,8 +718,8 @@ func decideColumnFormats(colTyps []oid.Oid, forceText bool) (colFmts []format, c
allBinary := true
allText := true
for i, o := range colTyps {
switch o {
for i, t := range colTyps {
switch t.OID {
// This is the list of types to use binary mode for when receiving them
// through a prepared statement. If a type appears in this list, it
// must also be implemented in binaryDecode in encode.go.
@@ -840,16 +839,15 @@ func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) {
rows.colNames, rows.colFmts, rows.colTyps = cn.readPortalDescribeResponse()
cn.postExecuteWorkaround()
return rows, nil
} else {
st := cn.prepareTo(query, "")
st.exec(args)
return &rows{
cn: cn,
colNames: st.colNames,
colTyps: st.colTyps,
colFmts: st.colFmts,
}, nil
}
st := cn.prepareTo(query, "")
st.exec(args)
return &rows{
cn: cn,
colNames: st.colNames,
colTyps: st.colTyps,
colFmts: st.colFmts,
}, nil
}
// Implement the optional "Execer" interface for one-shot queries
@@ -876,17 +874,16 @@ func (cn *conn) Exec(query string, args []driver.Value) (res driver.Result, err
cn.postExecuteWorkaround()
res, _, err = cn.readExecuteResponse("Execute")
return res, err
} else {
// Use the unnamed statement to defer planning until bind
// time, or else value-based selectivity estimates cannot be
// used.
st := cn.prepareTo(query, "")
r, err := st.Exec(args)
if err != nil {
panic(err)
}
return r, err
}
// Use the unnamed statement to defer planning until bind
// time, or else value-based selectivity estimates cannot be
// used.
st := cn.prepareTo(query, "")
r, err := st.Exec(args)
if err != nil {
panic(err)
}
return r, err
}
func (cn *conn) send(m *writeBuf) {
@@ -1147,10 +1144,10 @@ const formatText format = 0
const formatBinary format = 1
// One result-column format code with the value 1 (i.e. all binary).
var colFmtDataAllBinary []byte = []byte{0, 1, 0, 1}
var colFmtDataAllBinary = []byte{0, 1, 0, 1}
// No result-column format codes (i.e. all text).
var colFmtDataAllText []byte = []byte{0, 0}
var colFmtDataAllText = []byte{0, 0}
type stmt struct {
cn *conn
@@ -1158,7 +1155,7 @@ type stmt struct {
colNames []string
colFmts []format
colFmtData []byte
colTyps []oid.Oid
colTyps []fieldDesc
paramTyps []oid.Oid
closed bool
}
@@ -1321,7 +1318,7 @@ type rows struct {
cn *conn
finish func()
colNames []string
colTyps []oid.Oid
colTyps []fieldDesc
colFmts []format
done bool
rb readBuf
@@ -1409,7 +1406,7 @@ func (rs *rows) Next(dest []driver.Value) (err error) {
dest[i] = nil
continue
}
dest[i] = decode(&conn.parameterStatus, rs.rb.next(l), rs.colTyps[i], rs.colFmts[i])
dest[i] = decode(&conn.parameterStatus, rs.rb.next(l), rs.colTyps[i].OID, rs.colFmts[i])
}
return
case 'T':
@@ -1515,7 +1512,7 @@ func (cn *conn) sendBinaryModeQuery(query string, args []driver.Value) {
cn.send(b)
}
func (c *conn) processParameterStatus(r *readBuf) {
func (cn *conn) processParameterStatus(r *readBuf) {
var err error
param := r.string()
@@ -1526,13 +1523,13 @@ func (c *conn) processParameterStatus(r *readBuf) {
var minor int
_, err = fmt.Sscanf(r.string(), "%d.%d.%d", &major1, &major2, &minor)
if err == nil {
c.parameterStatus.serverVersion = major1*10000 + major2*100 + minor
cn.parameterStatus.serverVersion = major1*10000 + major2*100 + minor
}
case "TimeZone":
c.parameterStatus.currentLocation, err = time.LoadLocation(r.string())
cn.parameterStatus.currentLocation, err = time.LoadLocation(r.string())
if err != nil {
c.parameterStatus.currentLocation = nil
cn.parameterStatus.currentLocation = nil
}
default:
@@ -1540,8 +1537,8 @@ func (c *conn) processParameterStatus(r *readBuf) {
}
}
func (c *conn) processReadyForQuery(r *readBuf) {
c.txnStatus = transactionStatus(r.byte())
func (cn *conn) processReadyForQuery(r *readBuf) {
cn.txnStatus = transactionStatus(r.byte())
}
func (cn *conn) readReadyForQuery() {
@@ -1556,9 +1553,9 @@ func (cn *conn) readReadyForQuery() {
}
}
func (c *conn) processBackendKeyData(r *readBuf) {
c.processID = r.int32()
c.secretKey = r.int32()
func (cn *conn) processBackendKeyData(r *readBuf) {
cn.processID = r.int32()
cn.secretKey = r.int32()
}
func (cn *conn) readParseResponse() {
@@ -1576,7 +1573,7 @@ func (cn *conn) readParseResponse() {
}
}
func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames []string, colTyps []oid.Oid) {
func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames []string, colTyps []fieldDesc) {
for {
t, r := cn.recv1()
switch t {
@@ -1602,7 +1599,7 @@ func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames [
}
}
func (cn *conn) readPortalDescribeResponse() (colNames []string, colFmts []format, colTyps []oid.Oid) {
func (cn *conn) readPortalDescribeResponse() (colNames []string, colFmts []format, colTyps []fieldDesc) {
t, r := cn.recv1()
switch t {
case 'T':
@@ -1698,31 +1695,33 @@ func (cn *conn) readExecuteResponse(protocolState string) (res driver.Result, co
}
}
func parseStatementRowDescribe(r *readBuf) (colNames []string, colTyps []oid.Oid) {
func parseStatementRowDescribe(r *readBuf) (colNames []string, colTyps []fieldDesc) {
n := r.int16()
colNames = make([]string, n)
colTyps = make([]oid.Oid, n)
colTyps = make([]fieldDesc, n)
for i := range colNames {
colNames[i] = r.string()
r.next(6)
colTyps[i] = r.oid()
r.next(6)
colTyps[i].OID = r.oid()
colTyps[i].Len = r.int16()
colTyps[i].Mod = r.int32()
// format code not known when describing a statement; always 0
r.next(2)
}
return
}
func parsePortalRowDescribe(r *readBuf) (colNames []string, colFmts []format, colTyps []oid.Oid) {
func parsePortalRowDescribe(r *readBuf) (colNames []string, colFmts []format, colTyps []fieldDesc) {
n := r.int16()
colNames = make([]string, n)
colFmts = make([]format, n)
colTyps = make([]oid.Oid, n)
colTyps = make([]fieldDesc, n)
for i := range colNames {
colNames[i] = r.string()
r.next(6)
colTyps[i] = r.oid()
r.next(6)
colTyps[i].OID = r.oid()
colTyps[i].Len = r.int16()
colTyps[i].Mod = r.int32()
colFmts[i] = format(r.int16())
}
return

View File

@@ -1,147 +0,0 @@
package hstore
import (
"database/sql"
_ "github.com/lib/pq"
"os"
"testing"
)
type Fatalistic interface {
Fatal(args ...interface{})
}
func openTestConn(t Fatalistic) *sql.DB {
datname := os.Getenv("PGDATABASE")
sslmode := os.Getenv("PGSSLMODE")
if datname == "" {
os.Setenv("PGDATABASE", "pqgotest")
}
if sslmode == "" {
os.Setenv("PGSSLMODE", "disable")
}
conn, err := sql.Open("postgres", "")
if err != nil {
t.Fatal(err)
}
return conn
}
func TestHstore(t *testing.T) {
db := openTestConn(t)
defer db.Close()
// quitely create hstore if it doesn't exist
_, err := db.Exec("CREATE EXTENSION IF NOT EXISTS hstore")
if err != nil {
t.Skipf("Skipping hstore tests - hstore extension create failed: %s", err.Error())
}
hs := Hstore{}
// test for null-valued hstores
err = db.QueryRow("SELECT NULL::hstore").Scan(&hs)
if err != nil {
t.Fatal(err)
}
if hs.Map != nil {
t.Fatalf("expected null map")
}
err = db.QueryRow("SELECT $1::hstore", hs).Scan(&hs)
if err != nil {
t.Fatalf("re-query null map failed: %s", err.Error())
}
if hs.Map != nil {
t.Fatalf("expected null map")
}
// test for empty hstores
err = db.QueryRow("SELECT ''::hstore").Scan(&hs)
if err != nil {
t.Fatal(err)
}
if hs.Map == nil {
t.Fatalf("expected empty map, got null map")
}
if len(hs.Map) != 0 {
t.Fatalf("expected empty map, got len(map)=%d", len(hs.Map))
}
err = db.QueryRow("SELECT $1::hstore", hs).Scan(&hs)
if err != nil {
t.Fatalf("re-query empty map failed: %s", err.Error())
}
if hs.Map == nil {
t.Fatalf("expected empty map, got null map")
}
if len(hs.Map) != 0 {
t.Fatalf("expected empty map, got len(map)=%d", len(hs.Map))
}
// a few example maps to test out
hsOnePair := Hstore{
Map: map[string]sql.NullString{
"key1": {"value1", true},
},
}
hsThreePairs := Hstore{
Map: map[string]sql.NullString{
"key1": {"value1", true},
"key2": {"value2", true},
"key3": {"value3", true},
},
}
hsSmorgasbord := Hstore{
Map: map[string]sql.NullString{
"nullstring": {"NULL", true},
"actuallynull": {"", false},
"NULL": {"NULL string key", true},
"withbracket": {"value>42", true},
"withequal": {"value=42", true},
`"withquotes1"`: {`this "should" be fine`, true},
`"withquotes"2"`: {`this "should\" also be fine`, true},
"embedded1": {"value1=>x1", true},
"embedded2": {`"value2"=>x2`, true},
"withnewlines": {"\n\nvalue\t=>2", true},
"<<all sorts of crazy>>": {`this, "should,\" also, => be fine`, true},
},
}
// test encoding in query params, then decoding during Scan
testBidirectional := func(h Hstore) {
err = db.QueryRow("SELECT $1::hstore", h).Scan(&hs)
if err != nil {
t.Fatalf("re-query %d-pair map failed: %s", len(h.Map), err.Error())
}
if hs.Map == nil {
t.Fatalf("expected %d-pair map, got null map", len(h.Map))
}
if len(hs.Map) != len(h.Map) {
t.Fatalf("expected %d-pair map, got len(map)=%d", len(h.Map), len(hs.Map))
}
for key, val := range hs.Map {
otherval, found := h.Map[key]
if !found {
t.Fatalf(" key '%v' not found in %d-pair map", key, len(h.Map))
}
if otherval.Valid != val.Valid {
t.Fatalf(" value %v <> %v in %d-pair map", otherval, val, len(h.Map))
}
if otherval.String != val.String {
t.Fatalf(" value '%v' <> '%v' in %d-pair map", otherval.String, val.String, len(h.Map))
}
}
}
testBidirectional(hsOnePair)
testBidirectional(hsThreePairs)
testBidirectional(hsSmorgasbord)
}

View File

@@ -18,11 +18,11 @@ mechanism to avoid polling the database while waiting for more work to arrive.
package main
import (
"github.com/lib/pq"
"database/sql"
"fmt"
"time"
"github.com/lib/pq"
)
func doWork(db *sql.DB, work int64) {
@@ -51,21 +51,15 @@ mechanism to avoid polling the database while waiting for more work to arrive.
}
func waitForNotification(l *pq.Listener) {
for {
select {
case <-l.Notify:
fmt.Println("received notification, new work available")
return
case <-time.After(90 * time.Second):
go func() {
l.Ping()
}()
// Check if there's more work available, just in case it takes
// a while for the Listener to notice connection loss and
// reconnect.
fmt.Println("received no work for 90 seconds, checking for new work")
return
}
select {
case <-l.Notify:
fmt.Println("received notification, new work available")
case <-time.After(90 * time.Second):
go l.Ping()
// Check if there's more work available, just in case it takes
// a while for the Listener to notice connection loss and
// reconnect.
fmt.Println("received no work for 90 seconds, checking for new work")
}
}

74
vendor/github.com/lib/pq/oid/gen.go generated vendored
View File

@@ -1,74 +0,0 @@
// +build ignore
// Generate the table of OID values
// Run with 'go run gen.go'.
package main
import (
"fmt"
"log"
"os"
"os/exec"
"database/sql"
_ "github.com/lib/pq"
)
func main() {
datname := os.Getenv("PGDATABASE")
sslmode := os.Getenv("PGSSLMODE")
if datname == "" {
os.Setenv("PGDATABASE", "pqgotest")
}
if sslmode == "" {
os.Setenv("PGSSLMODE", "disable")
}
db, err := sql.Open("postgres", "")
if err != nil {
log.Fatal(err)
}
cmd := exec.Command("gofmt")
cmd.Stderr = os.Stderr
w, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
f, err := os.Create("types.go")
if err != nil {
log.Fatal(err)
}
cmd.Stdout = f
err = cmd.Start()
if err != nil {
log.Fatal(err)
}
fmt.Fprintln(w, "// generated by 'go run gen.go'; do not edit")
fmt.Fprintln(w, "\npackage oid")
fmt.Fprintln(w, "const (")
rows, err := db.Query(`
SELECT typname, oid
FROM pg_type WHERE oid < 10000
ORDER BY oid;
`)
if err != nil {
log.Fatal(err)
}
var name string
var oid int
for rows.Next() {
err = rows.Scan(&name, &oid)
if err != nil {
log.Fatal(err)
}
fmt.Fprintf(w, "T_%s Oid = %d\n", name, oid)
}
if err = rows.Err(); err != nil {
log.Fatal(err)
}
fmt.Fprintln(w, ")")
w.Close()
cmd.Wait()
}

184
vendor/github.com/lib/pq/oid/types.go generated vendored
View File

@@ -1,4 +1,4 @@
// generated by 'go run gen.go'; do not edit
// Code generated by gen.go. DO NOT EDIT.
package oid
@@ -18,6 +18,7 @@ const (
T_xid Oid = 28
T_cid Oid = 29
T_oidvector Oid = 30
T_pg_ddl_command Oid = 32
T_pg_type Oid = 71
T_pg_attribute Oid = 75
T_pg_proc Oid = 81
@@ -28,6 +29,7 @@ const (
T_pg_node_tree Oid = 194
T__json Oid = 199
T_smgr Oid = 210
T_index_am_handler Oid = 325
T_point Oid = 600
T_lseg Oid = 601
T_path Oid = 602
@@ -133,6 +135,9 @@ const (
T__uuid Oid = 2951
T_txid_snapshot Oid = 2970
T_fdw_handler Oid = 3115
T_pg_lsn Oid = 3220
T__pg_lsn Oid = 3221
T_tsm_handler Oid = 3310
T_anyenum Oid = 3500
T_tsvector Oid = 3614
T_tsquery Oid = 3615
@@ -144,6 +149,8 @@ const (
T__regconfig Oid = 3735
T_regdictionary Oid = 3769
T__regdictionary Oid = 3770
T_jsonb Oid = 3802
T__jsonb Oid = 3807
T_anyrange Oid = 3831
T_event_trigger Oid = 3838
T_int4range Oid = 3904
@@ -158,4 +165,179 @@ const (
T__daterange Oid = 3913
T_int8range Oid = 3926
T__int8range Oid = 3927
T_pg_shseclabel Oid = 4066
T_regnamespace Oid = 4089
T__regnamespace Oid = 4090
T_regrole Oid = 4096
T__regrole Oid = 4097
)
var TypeName = map[Oid]string{
T_bool: "BOOL",
T_bytea: "BYTEA",
T_char: "CHAR",
T_name: "NAME",
T_int8: "INT8",
T_int2: "INT2",
T_int2vector: "INT2VECTOR",
T_int4: "INT4",
T_regproc: "REGPROC",
T_text: "TEXT",
T_oid: "OID",
T_tid: "TID",
T_xid: "XID",
T_cid: "CID",
T_oidvector: "OIDVECTOR",
T_pg_ddl_command: "PG_DDL_COMMAND",
T_pg_type: "PG_TYPE",
T_pg_attribute: "PG_ATTRIBUTE",
T_pg_proc: "PG_PROC",
T_pg_class: "PG_CLASS",
T_json: "JSON",
T_xml: "XML",
T__xml: "_XML",
T_pg_node_tree: "PG_NODE_TREE",
T__json: "_JSON",
T_smgr: "SMGR",
T_index_am_handler: "INDEX_AM_HANDLER",
T_point: "POINT",
T_lseg: "LSEG",
T_path: "PATH",
T_box: "BOX",
T_polygon: "POLYGON",
T_line: "LINE",
T__line: "_LINE",
T_cidr: "CIDR",
T__cidr: "_CIDR",
T_float4: "FLOAT4",
T_float8: "FLOAT8",
T_abstime: "ABSTIME",
T_reltime: "RELTIME",
T_tinterval: "TINTERVAL",
T_unknown: "UNKNOWN",
T_circle: "CIRCLE",
T__circle: "_CIRCLE",
T_money: "MONEY",
T__money: "_MONEY",
T_macaddr: "MACADDR",
T_inet: "INET",
T__bool: "_BOOL",
T__bytea: "_BYTEA",
T__char: "_CHAR",
T__name: "_NAME",
T__int2: "_INT2",
T__int2vector: "_INT2VECTOR",
T__int4: "_INT4",
T__regproc: "_REGPROC",
T__text: "_TEXT",
T__tid: "_TID",
T__xid: "_XID",
T__cid: "_CID",
T__oidvector: "_OIDVECTOR",
T__bpchar: "_BPCHAR",
T__varchar: "_VARCHAR",
T__int8: "_INT8",
T__point: "_POINT",
T__lseg: "_LSEG",
T__path: "_PATH",
T__box: "_BOX",
T__float4: "_FLOAT4",
T__float8: "_FLOAT8",
T__abstime: "_ABSTIME",
T__reltime: "_RELTIME",
T__tinterval: "_TINTERVAL",
T__polygon: "_POLYGON",
T__oid: "_OID",
T_aclitem: "ACLITEM",
T__aclitem: "_ACLITEM",
T__macaddr: "_MACADDR",
T__inet: "_INET",
T_bpchar: "BPCHAR",
T_varchar: "VARCHAR",
T_date: "DATE",
T_time: "TIME",
T_timestamp: "TIMESTAMP",
T__timestamp: "_TIMESTAMP",
T__date: "_DATE",
T__time: "_TIME",
T_timestamptz: "TIMESTAMPTZ",
T__timestamptz: "_TIMESTAMPTZ",
T_interval: "INTERVAL",
T__interval: "_INTERVAL",
T__numeric: "_NUMERIC",
T_pg_database: "PG_DATABASE",
T__cstring: "_CSTRING",
T_timetz: "TIMETZ",
T__timetz: "_TIMETZ",
T_bit: "BIT",
T__bit: "_BIT",
T_varbit: "VARBIT",
T__varbit: "_VARBIT",
T_numeric: "NUMERIC",
T_refcursor: "REFCURSOR",
T__refcursor: "_REFCURSOR",
T_regprocedure: "REGPROCEDURE",
T_regoper: "REGOPER",
T_regoperator: "REGOPERATOR",
T_regclass: "REGCLASS",
T_regtype: "REGTYPE",
T__regprocedure: "_REGPROCEDURE",
T__regoper: "_REGOPER",
T__regoperator: "_REGOPERATOR",
T__regclass: "_REGCLASS",
T__regtype: "_REGTYPE",
T_record: "RECORD",
T_cstring: "CSTRING",
T_any: "ANY",
T_anyarray: "ANYARRAY",
T_void: "VOID",
T_trigger: "TRIGGER",
T_language_handler: "LANGUAGE_HANDLER",
T_internal: "INTERNAL",
T_opaque: "OPAQUE",
T_anyelement: "ANYELEMENT",
T__record: "_RECORD",
T_anynonarray: "ANYNONARRAY",
T_pg_authid: "PG_AUTHID",
T_pg_auth_members: "PG_AUTH_MEMBERS",
T__txid_snapshot: "_TXID_SNAPSHOT",
T_uuid: "UUID",
T__uuid: "_UUID",
T_txid_snapshot: "TXID_SNAPSHOT",
T_fdw_handler: "FDW_HANDLER",
T_pg_lsn: "PG_LSN",
T__pg_lsn: "_PG_LSN",
T_tsm_handler: "TSM_HANDLER",
T_anyenum: "ANYENUM",
T_tsvector: "TSVECTOR",
T_tsquery: "TSQUERY",
T_gtsvector: "GTSVECTOR",
T__tsvector: "_TSVECTOR",
T__gtsvector: "_GTSVECTOR",
T__tsquery: "_TSQUERY",
T_regconfig: "REGCONFIG",
T__regconfig: "_REGCONFIG",
T_regdictionary: "REGDICTIONARY",
T__regdictionary: "_REGDICTIONARY",
T_jsonb: "JSONB",
T__jsonb: "_JSONB",
T_anyrange: "ANYRANGE",
T_event_trigger: "EVENT_TRIGGER",
T_int4range: "INT4RANGE",
T__int4range: "_INT4RANGE",
T_numrange: "NUMRANGE",
T__numrange: "_NUMRANGE",
T_tsrange: "TSRANGE",
T__tsrange: "_TSRANGE",
T_tstzrange: "TSTZRANGE",
T__tstzrange: "_TSTZRANGE",
T_daterange: "DATERANGE",
T__daterange: "_DATERANGE",
T_int8range: "INT8RANGE",
T__int8range: "_INT8RANGE",
T_pg_shseclabel: "PG_SHSECLABEL",
T_regnamespace: "REGNAMESPACE",
T__regnamespace: "_REGNAMESPACE",
T_regrole: "REGROLE",
T__regrole: "_REGROLE",
}

93
vendor/github.com/lib/pq/rows.go generated vendored Normal file
View File

@@ -0,0 +1,93 @@
package pq
import (
"math"
"reflect"
"time"
"github.com/lib/pq/oid"
)
const headerSize = 4
type fieldDesc struct {
// The object ID of the data type.
OID oid.Oid
// The data type size (see pg_type.typlen).
// Note that negative values denote variable-width types.
Len int
// The type modifier (see pg_attribute.atttypmod).
// The meaning of the modifier is type-specific.
Mod int
}
func (fd fieldDesc) Type() reflect.Type {
switch fd.OID {
case oid.T_int8:
return reflect.TypeOf(int64(0))
case oid.T_int4:
return reflect.TypeOf(int32(0))
case oid.T_int2:
return reflect.TypeOf(int16(0))
case oid.T_varchar, oid.T_text:
return reflect.TypeOf("")
case oid.T_bool:
return reflect.TypeOf(false)
case oid.T_date, oid.T_time, oid.T_timetz, oid.T_timestamp, oid.T_timestamptz:
return reflect.TypeOf(time.Time{})
case oid.T_bytea:
return reflect.TypeOf([]byte(nil))
default:
return reflect.TypeOf(new(interface{})).Elem()
}
}
func (fd fieldDesc) Name() string {
return oid.TypeName[fd.OID]
}
func (fd fieldDesc) Length() (length int64, ok bool) {
switch fd.OID {
case oid.T_text, oid.T_bytea:
return math.MaxInt64, true
case oid.T_varchar, oid.T_bpchar:
return int64(fd.Mod - headerSize), true
default:
return 0, false
}
}
func (fd fieldDesc) PrecisionScale() (precision, scale int64, ok bool) {
switch fd.OID {
case oid.T_numeric, oid.T__numeric:
mod := fd.Mod - headerSize
precision = int64((mod >> 16) & 0xffff)
scale = int64(mod & 0xffff)
return precision, scale, true
default:
return 0, 0, false
}
}
// ColumnTypeScanType returns the value type that can be used to scan types into.
func (rs *rows) ColumnTypeScanType(index int) reflect.Type {
return rs.colTyps[index].Type()
}
// ColumnTypeDatabaseTypeName return the database system type name.
func (rs *rows) ColumnTypeDatabaseTypeName(index int) string {
return rs.colTyps[index].Name()
}
// ColumnTypeLength returns the length of the column type if the column is a
// variable length type. If the column is not a variable length type ok
// should return false.
func (rs *rows) ColumnTypeLength(index int) (length int64, ok bool) {
return rs.colTyps[index].Length()
}
// ColumnTypePrecisionScale should return the precision and scale for decimal
// types. If not applicable, ok should be false.
func (rs *rows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) {
return rs.colTyps[index].PrecisionScale()
}

27
vendor/vendor.json vendored
View File

@@ -461,10 +461,31 @@
"revisionTime": "2017-02-10T14:05:23Z"
},
{
"checksumSHA1": "ZAj/o03zG8Ui4mZ4XmzU4yyKC04=",
"checksumSHA1": "RYMOEINLFNWIJk8aKNifSlPhg9U=",
"path": "github.com/lib/pq",
"revision": "dd1fe2071026ce53f36a39112e645b4d4f5793a4",
"revisionTime": "2017-07-07T05:36:02Z"
"revision": "23da1db4f16d9658a86ae9b717c245fc078f10f1",
"revisionTime": "2017-09-18T17:50:43Z"
},
{
"checksumSHA1": "jaCQF1par6Jl8g+V2Cgp0n/0wSc=",
"origin": "github.com/grafana/grafana/vendor/github.com/lib/pq/hstore",
"path": "github.com/lib/pq/hstore",
"revision": "23da1db4f16d9658a86ae9b717c245fc078f10f1",
"revisionTime": "2017-09-18T17:50:43Z"
},
{
"checksumSHA1": "mJHrY33tDs2MRhHt+XunkRF/5ek=",
"origin": "github.com/grafana/grafana/vendor/github.com/lib/pq/listen_example",
"path": "github.com/lib/pq/listen_example",
"revision": "23da1db4f16d9658a86ae9b717c245fc078f10f1",
"revisionTime": "2017-09-18T17:50:43Z"
},
{
"checksumSHA1": "AU3fA8Sm33Vj9PBoRPSeYfxLRuE=",
"origin": "github.com/grafana/grafana/vendor/github.com/lib/pq/oid",
"path": "github.com/lib/pq/oid",
"revision": "23da1db4f16d9658a86ae9b717c245fc078f10f1",
"revisionTime": "2017-09-18T17:50:43Z"
},
{
"checksumSHA1": "bKMZjd2wPw13VwoE7mBeSv5djFA=",