Support unknown PostgreSQL types as strings

This commit is contained in:
Jack Christensen 2014-07-19 17:49:11 -05:00
parent 6b78c7aa34
commit 3144b5363f
3 changed files with 60 additions and 12 deletions

10
conn.go
View File

@ -470,14 +470,14 @@ func (c *Conn) sendPreparedQuery(ps *PreparedStatement, arguments ...interface{}
switch arg := arguments[i].(type) { switch arg := arguments[i].(type) {
case Encoder: case Encoder:
wbuf.WriteInt16(arg.FormatCode()) wbuf.WriteInt16(arg.FormatCode())
case string:
wbuf.WriteInt16(TextFormatCode)
default: default:
switch oid { switch oid {
case BoolOid, ByteaOid, Int2Oid, Int4Oid, Int8Oid, Float4Oid, Float8Oid, TimestampTzOid: case BoolOid, ByteaOid, Int2Oid, Int4Oid, Int8Oid, Float4Oid, Float8Oid, TimestampTzOid:
wbuf.WriteInt16(BinaryFormatCode) wbuf.WriteInt16(BinaryFormatCode)
case TextOid, VarcharOid, DateOid, TimestampOid:
wbuf.WriteInt16(TextFormatCode)
default: default:
return SerializationError(fmt.Sprintf("Parameter %d oid %d is not a core type and argument type %T does not implement TextEncoder or BinaryEncoder", i, oid, arg)) wbuf.WriteInt16(TextFormatCode)
} }
} }
} }
@ -492,6 +492,8 @@ func (c *Conn) sendPreparedQuery(ps *PreparedStatement, arguments ...interface{}
switch arg := arguments[i].(type) { switch arg := arguments[i].(type) {
case Encoder: case Encoder:
err = arg.Encode(wbuf, oid) err = arg.Encode(wbuf, oid)
case string:
err = encodeText(wbuf, arguments[i])
default: default:
switch oid { switch oid {
case BoolOid: case BoolOid:
@ -517,7 +519,7 @@ func (c *Conn) sendPreparedQuery(ps *PreparedStatement, arguments ...interface{}
case TimestampOid: case TimestampOid:
err = encodeTimestamp(wbuf, arguments[i]) err = encodeTimestamp(wbuf, arguments[i])
default: default:
return SerializationError(fmt.Sprintf("%T is not a core type and it does not implement TextEncoder or BinaryEncoder", arg)) return SerializationError(fmt.Sprintf("%T is not a core type and it does not implement Encoder", arg))
} }
} }
if err != nil { if err != nil {

View File

@ -272,14 +272,19 @@ func TestQueryEncodeError(t *testing.T) {
conn := mustConnect(t, *defaultConnConfig) conn := mustConnect(t, *defaultConnConfig)
defer closeConn(t, conn) defer closeConn(t, conn)
_, err := conn.Query("select $1::integer", "wrong") rows, err := conn.Query("select $1::integer", "wrong")
switch { if err != nil {
case err == nil: t.Errorf("conn.Query failure: %v", err)
t.Error("Expected transcode error to return error, but it didn't") }
case err.Error() == "Expected integer representable in int32, received string wrong": defer rows.Close()
// Correct behavior
default: rows.Next()
t.Errorf("Expected transcode error, received %v", err)
if rows.Err() == nil {
t.Error("Expected rows.Err() to return error, but it didn't")
}
if rows.Err().Error() != `ERROR: invalid input syntax for integer: "wrong" (SQLSTATE 22P02)` {
t.Error("Expected rows.Err() to return different error:", rows.Err())
} }
} }
@ -399,6 +404,29 @@ func TestQueryRowCoreBytea(t *testing.T) {
ensureConnValid(t, conn) ensureConnValid(t, conn)
} }
func TestQueryRowUnknownType(t *testing.T) {
t.Parallel()
conn := mustConnect(t, *defaultConnConfig)
defer closeConn(t, conn)
sql := "select $1::inet"
expected := "127.0.0.1"
var actual string
err := conn.QueryRow(sql, expected).Scan(&actual)
if err != nil {
t.Errorf("Unexpected failure: %v (sql -> %v)", err, sql)
}
if actual != expected {
t.Errorf(`Expected "%v", got "%v" (sql -> %v)`, expected, actual, sql)
}
ensureConnValid(t, conn)
}
func TestQueryRowErrors(t *testing.T) { func TestQueryRowErrors(t *testing.T) {
t.Parallel() t.Parallel()

View File

@ -295,6 +295,24 @@ func TestConnQueryFailure(t *testing.T) {
} }
} }
func TestConnQueryRowUnknownType(t *testing.T) {
db := openDB(t)
defer closeDB(t, db)
sql := "select $1::inet"
expected := "127.0.0.1"
var actual string
err := db.QueryRow(sql, expected).Scan(&actual)
if err != nil {
t.Errorf("Unexpected failure: %v (sql -> %v)", err, sql)
}
if actual != expected {
t.Errorf(`Expected "%v", got "%v" (sql -> %v)`, expected, actual, sql)
}
}
func TestTransactionLifeCycle(t *testing.T) { func TestTransactionLifeCycle(t *testing.T) {
db := openDB(t) db := openDB(t)
defer closeDB(t, db) defer closeDB(t, db)