PostgreSQL: Remove feature toggle postgresDSUsePGX (#113675)
* PostgreSQL: Remove feature toggle `postgresDSUsePGX` * Fix tests and linting * Address review comments
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
@@ -15,20 +15,14 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tsdb/grafana-postgresql-datasource/sqleng"
|
||||
|
||||
"github.com/grafana/grafana/pkg/util/testutil"
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
// Test generateConnectionString.
|
||||
func TestIntegrationGenerateConnectionString(t *testing.T) {
|
||||
testutil.SkipIntegrationTestInShortMode(t)
|
||||
|
||||
cfg := setting.NewCfg()
|
||||
cfg.DataPath = t.TempDir()
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
host string
|
||||
@@ -58,15 +52,6 @@ func TestIntegrationGenerateConnectionString(t *testing.T) {
|
||||
tlsSettings: tlsSettings{Mode: "verify-full"},
|
||||
expConnStr: "user='user' host='host' dbname='database' password='password' sslmode='verify-full'",
|
||||
},
|
||||
{
|
||||
desc: "verify-ca automatically adds disable-sni",
|
||||
host: "host:1234",
|
||||
user: "user",
|
||||
password: "password",
|
||||
database: "database",
|
||||
tlsSettings: tlsSettings{Mode: "verify-ca"},
|
||||
expConnStr: "user='user' host='host' dbname='database' password='password' port=1234 sslmode='verify-ca' sslsni=0",
|
||||
},
|
||||
{
|
||||
desc: "TCP/port host",
|
||||
host: "host:1234",
|
||||
@@ -156,8 +141,6 @@ func TestIntegrationGenerateConnectionString(t *testing.T) {
|
||||
}
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
logger := backend.NewLoggerWith("logger", "tsdb.postgres")
|
||||
|
||||
ds := sqleng.DataSourceInfo{
|
||||
URL: tt.host,
|
||||
User: tt.user,
|
||||
@@ -165,8 +148,9 @@ func TestIntegrationGenerateConnectionString(t *testing.T) {
|
||||
Database: tt.database,
|
||||
UID: tt.uid,
|
||||
}
|
||||
logger := backend.NewLoggerWith("logger", "tsdb.postgres")
|
||||
|
||||
connStr, err := generateConnectionString(ds, tt.tlsSettings, false, logger)
|
||||
connStr, err := generateConnectionString(ds, tt.tlsSettings, logger)
|
||||
|
||||
if tt.expErr == "" {
|
||||
require.NoError(t, err, tt.desc)
|
||||
@@ -207,10 +191,11 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
}
|
||||
|
||||
jsonData := sqleng.JsonData{
|
||||
MaxOpenConns: 0,
|
||||
MaxOpenConns: 10,
|
||||
MaxIdleConns: 2,
|
||||
ConnMaxLifetime: 14400,
|
||||
Timescaledb: false,
|
||||
Mode: "disable",
|
||||
ConfigurationMethod: "file-path",
|
||||
}
|
||||
|
||||
@@ -223,7 +208,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
|
||||
cnnstr := postgresTestDBConnString()
|
||||
|
||||
db, exe, err := newPostgres(context.Background(), "error", 10000, dsInfo, cnnstr, logger, backend.DataSourceInstanceSettings{})
|
||||
p, exe, err := newPostgres(t.Context(), "error", 10000, dsInfo, cnnstr, logger, backend.DataSourceInstanceSettings{})
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -253,10 +238,13 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
c14_timetz time with time zone,
|
||||
time date,
|
||||
c15_interval interval,
|
||||
c16_smallint smallint
|
||||
c16_smallint smallint,
|
||||
|
||||
c17_json json,
|
||||
c18_jsonb jsonb
|
||||
);
|
||||
`
|
||||
_, err := db.Exec(sql)
|
||||
_, err := p.Exec(t.Context(), sql)
|
||||
require.NoError(t, err)
|
||||
|
||||
sql = `
|
||||
@@ -264,12 +252,11 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
1,2,3,
|
||||
4.5,6.7,1.1,1.2,
|
||||
'char10','varchar10','text',
|
||||
|
||||
now(),now(),now(),now(),now(),now(),'15m'::interval,
|
||||
null
|
||||
now(),now(),now(),now(),now(),now(),'15m'::interval,null,
|
||||
'{"key1": "value1"}'::json, '{"key2": "value2"}'::jsonb
|
||||
);
|
||||
`
|
||||
_, err = db.Exec(sql)
|
||||
_, err = p.Exec(t.Context(), sql)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("When doing a table query should map Postgres column types to Go types", func(t *testing.T) {
|
||||
@@ -284,14 +271,14 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
|
||||
frames := queryResult.Frames
|
||||
require.Len(t, frames, 1)
|
||||
require.Len(t, frames[0].Fields, 18)
|
||||
require.Len(t, frames[0].Fields, 20)
|
||||
|
||||
require.Equal(t, int16(1), *frames[0].Fields[0].At(0).(*int16))
|
||||
require.Equal(t, int32(2), *frames[0].Fields[1].At(0).(*int32))
|
||||
@@ -312,14 +299,21 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
require.True(t, ok)
|
||||
_, ok = frames[0].Fields[12].At(0).(*time.Time)
|
||||
require.True(t, ok)
|
||||
_, ok = frames[0].Fields[13].At(0).(*time.Time)
|
||||
_, ok = frames[0].Fields[13].At(0).(*string)
|
||||
require.True(t, ok)
|
||||
_, ok = frames[0].Fields[14].At(0).(*time.Time)
|
||||
_, ok = frames[0].Fields[14].At(0).(*string)
|
||||
require.True(t, ok)
|
||||
_, ok = frames[0].Fields[15].At(0).(*time.Time)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "00:15:00", *frames[0].Fields[16].At(0).(*string))
|
||||
require.Nil(t, frames[0].Fields[17].At(0))
|
||||
|
||||
_, ok = frames[0].Fields[18].At(0).(*json.RawMessage)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, json.RawMessage(`{"key1": "value1"}`), *frames[0].Fields[18].At(0).(*json.RawMessage))
|
||||
_, ok = frames[0].Fields[19].At(0).(*json.RawMessage)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, json.RawMessage(`{"key2": "value2"}`), *frames[0].Fields[19].At(0).(*json.RawMessage))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -332,7 +326,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
)
|
||||
`
|
||||
|
||||
_, err := db.Exec(sql)
|
||||
_, err := p.Exec(t.Context(), sql)
|
||||
require.NoError(t, err)
|
||||
|
||||
type metric struct {
|
||||
@@ -359,7 +353,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, m := range series {
|
||||
_, err := db.Exec(`INSERT INTO metric ("time", value) VALUES ($1, $2)`, m.Time.UTC(), m.Value)
|
||||
_, err := p.Exec(t.Context(), `INSERT INTO metric ("time", value) VALUES ($1, $2)`, m.Time.UTC(), m.Value)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -376,7 +370,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -408,6 +402,27 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("When doing a query without a format should default to time_series", func(t *testing.T) {
|
||||
query := &backend.QueryDataRequest{
|
||||
Queries: []backend.DataQuery{
|
||||
{
|
||||
JSON: []byte(`{
|
||||
"rawSql": "SELECT $__timeGroup(time, '5m') AS time, avg(value) as value FROM metric GROUP BY 1 ORDER BY 1 "
|
||||
}`),
|
||||
RefID: "A",
|
||||
},
|
||||
},
|
||||
}
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
|
||||
frames := queryResult.Frames
|
||||
require.Len(t, frames, 1)
|
||||
require.Len(t, frames[0].Fields, 2)
|
||||
})
|
||||
|
||||
t.Run("When doing a metric query using timeGroup and $__interval", func(t *testing.T) {
|
||||
mockInterpolate := sqleng.Interpolate
|
||||
sqleng.Interpolate = origInterpolate
|
||||
@@ -432,7 +447,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
frames := queryResult.Frames
|
||||
@@ -460,7 +475,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -514,7 +529,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -540,7 +555,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, m := range series {
|
||||
_, err := db.Exec(`INSERT INTO metric ("time", value) VALUES ($1, $2)`, m.Time.UTC(), m.Value)
|
||||
_, err := p.Exec(t.Context(), `INSERT INTO metric ("time", value) VALUES ($1, $2)`, m.Time.UTC(), m.Value)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -561,7 +576,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -596,7 +611,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -624,10 +639,10 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
ValueTwo int64
|
||||
}
|
||||
|
||||
_, err := db.Exec("DROP TABLE IF EXISTS metric_values")
|
||||
_, err := p.Exec(t.Context(), "DROP TABLE IF EXISTS metric_values")
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = db.Exec(`CREATE TABLE metric_values (
|
||||
_, err = p.Exec(t.Context(), `CREATE TABLE metric_values (
|
||||
"time" TIMESTAMP NULL,
|
||||
"timeInt64" BIGINT NOT NULL, "timeInt64Nullable" BIGINT NULL,
|
||||
"timeFloat64" DOUBLE PRECISION NOT NULL, "timeFloat64Nullable" DOUBLE PRECISION NULL,
|
||||
@@ -680,7 +695,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
|
||||
// _, err = session.InsertMulti(series)
|
||||
for _, m := range series {
|
||||
_, err := db.Exec(`INSERT INTO "metric_values" (
|
||||
_, err := p.Exec(t.Context(), `INSERT INTO "metric_values" (
|
||||
time,
|
||||
"timeInt64", "timeInt64Nullable",
|
||||
"timeFloat64", "timeFloat64Nullable",
|
||||
@@ -713,7 +728,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -737,7 +752,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -761,7 +776,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -785,7 +800,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -809,7 +824,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -833,7 +848,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -857,7 +872,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -882,7 +897,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -906,7 +921,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -931,7 +946,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -963,7 +978,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -998,7 +1013,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -1017,9 +1032,9 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
Tags string
|
||||
}
|
||||
|
||||
_, err := db.Exec("DROP TABLE IF EXISTS event")
|
||||
_, err := p.Exec(t.Context(), "DROP TABLE IF EXISTS event")
|
||||
require.NoError(t, err)
|
||||
_, err = db.Exec(`CREATE TABLE event (time_sec BIGINT NULL, description VARCHAR(255) NULL, tags VARCHAR(255) NULL)`)
|
||||
_, err = p.Exec(t.Context(), `CREATE TABLE event (time_sec BIGINT NULL, description VARCHAR(255) NULL, tags VARCHAR(255) NULL)`)
|
||||
require.NoError(t, err)
|
||||
|
||||
events := []*event{}
|
||||
@@ -1037,7 +1052,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, e := range events {
|
||||
_, err := db.Exec("INSERT INTO event (time_sec, description, tags) VALUES ($1, $2, $3)", e.TimeSec, e.Description, e.Tags)
|
||||
_, err := p.Exec(t.Context(), "INSERT INTO event (time_sec, description, tags) VALUES ($1, $2, $3)", e.TimeSec, e.Description, e.Tags)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -1058,7 +1073,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
|
||||
queryResult := resp.Responses["Deploys"]
|
||||
@@ -1085,7 +1100,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
|
||||
queryResult := resp.Responses["Tickets"]
|
||||
@@ -1108,7 +1123,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -1133,7 +1148,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -1158,7 +1173,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -1184,7 +1199,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -1210,7 +1225,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -1236,7 +1251,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -1262,7 +1277,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -1276,8 +1291,20 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("When row limit set to 1", func(t *testing.T) {
|
||||
dsInfo := sqleng.DataSourceInfo{}
|
||||
_, handler, err := newPostgres(context.Background(), "error", 1, dsInfo, cnnstr, logger, backend.DataSourceInstanceSettings{})
|
||||
jsonData := sqleng.JsonData{
|
||||
MaxOpenConns: 10,
|
||||
MaxIdleConns: 2,
|
||||
ConnMaxLifetime: 14400,
|
||||
Timescaledb: false,
|
||||
Mode: "disable",
|
||||
ConfigurationMethod: "file-path",
|
||||
}
|
||||
|
||||
dsInfo := sqleng.DataSourceInfo{
|
||||
JsonData: jsonData,
|
||||
DecryptedSecureJSONData: map[string]string{},
|
||||
}
|
||||
_, handler, err := newPostgres(t.Context(), "error", 1, dsInfo, cnnstr, logger, backend.DataSourceInstanceSettings{})
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -1298,7 +1325,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := handler.QueryData(context.Background(), query)
|
||||
resp, err := handler.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -1328,7 +1355,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := handler.QueryData(context.Background(), query)
|
||||
resp, err := handler.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
@@ -1344,9 +1371,9 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Given an empty table", func(t *testing.T) {
|
||||
_, err := db.Exec("DROP TABLE IF EXISTS empty_obj")
|
||||
_, err := p.Exec(t.Context(), "DROP TABLE IF EXISTS empty_obj")
|
||||
require.NoError(t, err)
|
||||
_, err = db.Exec("CREATE TABLE empty_obj (empty_key VARCHAR(255) NULL, empty_val BIGINT NULL)")
|
||||
_, err = p.Exec(t.Context(), "CREATE TABLE empty_obj (empty_key VARCHAR(255) NULL, empty_val BIGINT NULL)")
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("When no rows are returned, should return an empty frame", func(t *testing.T) {
|
||||
@@ -1366,7 +1393,7 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := exe.QueryData(context.Background(), query)
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
|
||||
@@ -1376,6 +1403,154 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
require.NotNil(t, frames[0].Fields)
|
||||
require.Empty(t, frames[0].Fields)
|
||||
})
|
||||
|
||||
t.Run("Should handle multiple result sets without panicking", func(t *testing.T) {
|
||||
// Create a test table for the panic scenario test
|
||||
sql := `
|
||||
DROP TABLE IF EXISTS test_multi_results;
|
||||
CREATE TABLE test_multi_results(
|
||||
id integer,
|
||||
name text,
|
||||
value numeric
|
||||
);
|
||||
INSERT INTO test_multi_results VALUES
|
||||
(1, 'test1', 10.5),
|
||||
(2, 'test2', 20.7),
|
||||
(3, 'test3', 30.2);
|
||||
`
|
||||
_, err := p.Exec(t.Context(), sql)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Should handle compatible multiple result sets", func(t *testing.T) {
|
||||
// This query returns multiple result sets with the same structure
|
||||
query := &backend.QueryDataRequest{
|
||||
Queries: []backend.DataQuery{
|
||||
{
|
||||
RefID: "A",
|
||||
JSON: []byte(`{
|
||||
"rawSql": "SELECT id, name FROM test_multi_results WHERE id <= 2; SELECT id, name FROM test_multi_results WHERE id >= 2;",
|
||||
"format": "table"
|
||||
}`),
|
||||
TimeRange: backend.TimeRange{
|
||||
From: fromStart,
|
||||
To: fromStart.Add(1 * time.Hour),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// This should not panic and should work correctly
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
|
||||
frames := queryResult.Frames
|
||||
require.Len(t, frames, 1)
|
||||
|
||||
// The frame should be properly constructed from both SELECT results
|
||||
frame := frames[0]
|
||||
require.Equal(t, 2, len(frame.Fields)) // id, name from both queries
|
||||
require.Equal(t, "id", frame.Fields[0].Name)
|
||||
require.Equal(t, "name", frame.Fields[1].Name)
|
||||
require.Equal(t, 4, frame.Rows()) // 2 rows from first result + 2 rows from second result
|
||||
})
|
||||
|
||||
t.Run("Should return error for incompatible multiple result sets", func(t *testing.T) {
|
||||
// This query returns multiple result sets with different structures - the kind that used to cause panic
|
||||
query := &backend.QueryDataRequest{
|
||||
Queries: []backend.DataQuery{
|
||||
{
|
||||
RefID: "A",
|
||||
JSON: []byte(`{
|
||||
"rawSql": "SELECT id, name FROM test_multi_results WHERE id <= 2; SELECT id, value FROM test_multi_results WHERE id >= 2;",
|
||||
"format": "table"
|
||||
}`),
|
||||
TimeRange: backend.TimeRange{
|
||||
From: fromStart,
|
||||
To: fromStart.Add(1 * time.Hour),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// This should not panic anymore, but should return an error instead
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
|
||||
// We expect an error about column mismatch, not a panic
|
||||
require.Error(t, queryResult.Error)
|
||||
require.Contains(t, queryResult.Error.Error(), "column name mismatch")
|
||||
})
|
||||
|
||||
t.Run("Should return error for incompatible number of columns", func(t *testing.T) {
|
||||
// This query returns multiple result sets with different number of columns
|
||||
// This should fix the error "runtime error: index out of range [1] with length 1"
|
||||
query := &backend.QueryDataRequest{
|
||||
Queries: []backend.DataQuery{
|
||||
{
|
||||
RefID: "A",
|
||||
JSON: []byte(`{
|
||||
"rawSql": "SELECT id, name FROM test_multi_results WHERE id = 1; SELECT id FROM test_multi_results WHERE id = 1;",
|
||||
"format": "table"
|
||||
}`),
|
||||
TimeRange: backend.TimeRange{
|
||||
From: fromStart,
|
||||
To: fromStart.Add(1 * time.Hour),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// This should not panic anymore, but should return an error instead
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
|
||||
// We expect an error about incompatible result structure, not a panic
|
||||
require.Error(t, queryResult.Error)
|
||||
require.Contains(t, queryResult.Error.Error(), "incompatible result structure: expected 2 columns, got 1 columns")
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Should handle queries with mixed statement types", func(t *testing.T) {
|
||||
// This tests a scenario with UPDATE + SELECT that could cause the original panic
|
||||
query := &backend.QueryDataRequest{
|
||||
Queries: []backend.DataQuery{
|
||||
{
|
||||
RefID: "A",
|
||||
JSON: []byte(`{
|
||||
"rawSql": "UPDATE test_multi_results SET name = 'updated' WHERE id = 1; SELECT id, name FROM test_multi_results WHERE id = 1;",
|
||||
"format": "table"
|
||||
}`),
|
||||
TimeRange: backend.TimeRange{
|
||||
From: fromStart,
|
||||
To: fromStart.Add(1 * time.Hour),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// This should not panic
|
||||
resp, err := exe.QueryData(t.Context(), query)
|
||||
require.NoError(t, err)
|
||||
queryResult := resp.Responses["A"]
|
||||
require.NoError(t, queryResult.Error)
|
||||
|
||||
frames := queryResult.Frames
|
||||
require.Len(t, frames, 1)
|
||||
|
||||
// Should only contain data from the SELECT part
|
||||
frame := frames[0]
|
||||
require.Equal(t, 2, len(frame.Fields)) // id, name
|
||||
require.Equal(t, 1, frame.Rows()) // 1 row
|
||||
|
||||
// Verify the update worked
|
||||
nameField := frame.Fields[1]
|
||||
nameValue := nameField.At(0).(*string)
|
||||
require.Equal(t, "updated", *nameValue)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Test Postgres connection with pgpass file", func(t *testing.T) {
|
||||
@@ -1385,10 +1560,10 @@ func TestIntegrationPostgres(t *testing.T) {
|
||||
cnnstr := postgresTestDBConnString()
|
||||
require.NotContains(t, cnnstr, "password=", "Make sure that password is not in the connection string")
|
||||
|
||||
dbPgpass, _, err := newPostgres(context.Background(), "error", 10000, dsInfo, cnnstr, logger, backend.DataSourceInstanceSettings{})
|
||||
pgpassPool, _, err := newPostgres(t.Context(), "error", 10000, dsInfo, cnnstr, logger, backend.DataSourceInstanceSettings{})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = dbPgpass.Exec("SELECT 1") // Test connection
|
||||
_, err = pgpassPool.Query(t.Context(), "SELECT 1") // Test connection
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user