Skip to content

Commit 22c7272

Browse files
committed
fix: correlation column stats on < PG18
1 parent 9b3c017 commit 22c7272

2 files changed

Lines changed: 24 additions & 69 deletions

File tree

internal/schema/inject.go

Lines changed: 23 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,9 @@ func injectRelationStats(ctx context.Context, tx pgx.Tx, pgMajor int, schemaName
189189
func injectColumnStatsPG18(ctx context.Context, tx pgx.Tx, pgMajor int, schemaName, tableName string, col Column, s *ColumnStats) error {
190190
parts := []string{
191191
"'version', $1::int",
192-
"'schemaname', $2::name",
193-
"'relname', $3::name",
194-
"'attname', $4::name",
192+
"'schemaname', $2::text",
193+
"'relname', $3::text",
194+
"'attname', $4::text",
195195
"'inherited', false",
196196
}
197197
args := []any{pgMajor, schemaName, tableName, col.Name}
@@ -212,7 +212,7 @@ func injectColumnStatsPG18(ctx context.Context, tx pgx.Tx, pgMajor int, schemaNa
212212
parts = append(parts, fmt.Sprintf("'most_common_vals', $%d::text", idx))
213213
args = append(args, *s.MostCommonVals)
214214
idx++
215-
parts = append(parts, fmt.Sprintf("'most_common_freqs', $%d::text", idx))
215+
parts = append(parts, fmt.Sprintf("'most_common_freqs', $%d::real[]", idx))
216216
args = append(args, *s.MostCommonFreqs)
217217
idx++
218218
}
@@ -247,76 +247,31 @@ func injectColumnStatsLegacy(ctx context.Context, tx pgx.Tx, cm columnMeta, s *C
247247
nDistinct = float32(*s.NDistinct)
248248
}
249249

250-
// build slot values; types without equality op (json, xml, ...) can't have MCV or histogram slots
251-
type slot struct {
252-
kind int16
253-
op uint32
254-
numbers string
255-
values string
256-
}
257-
258-
hasEqOp := cm.eqOpOID != 0
259-
slots := [5]slot{}
260-
261-
if hasEqOp && s.MostCommonVals != nil && s.MostCommonFreqs != nil {
262-
slots[0] = slot{kind: 1, op: cm.eqOpOID, numbers: *s.MostCommonFreqs, values: *s.MostCommonVals}
263-
}
264-
if hasEqOp && s.HistogramBounds != nil {
265-
slots[1] = slot{kind: 2, op: cm.eqOpOID, values: *s.HistogramBounds}
266-
}
250+
// stavalues is anyarray Does not work before PG 18
251+
kind3 := int16(0)
252+
var correlation any
267253
if s.Correlation != nil {
268-
slots[2] = slot{kind: 3, numbers: fmt.Sprintf("{%v}", *s.Correlation)}
269-
}
270-
271-
arrayCast := cm.typeName + "[]"
272-
if strings.Contains(cm.typeName, " ") {
273-
arrayCast = fmt.Sprintf(`"%s"[]`, cm.typeName)
274-
}
275-
276-
var valueParts []string
277-
var args []any
278-
argN := 1
279-
280-
addArg := func(v any) string {
281-
placeholder := fmt.Sprintf("$%d", argN)
282-
args = append(args, v)
283-
argN++
284-
return placeholder
285-
}
286-
287-
valueParts = append(valueParts, addArg(cm.relOID), addArg(cm.attNum), "false", addArg(nullFrac), "0", addArg(nDistinct))
288-
289-
for _, sl := range slots {
290-
valueParts = append(valueParts, addArg(sl.kind))
291-
valueParts = append(valueParts, addArg(sl.op))
292-
293-
if sl.numbers != "" {
294-
valueParts = append(valueParts, addArg(sl.numbers)+"::real[]")
295-
} else {
296-
valueParts = append(valueParts, "NULL")
297-
}
298-
299-
if sl.values != "" {
300-
valueParts = append(valueParts, addArg(sl.values)+"::"+arrayCast)
301-
} else {
302-
valueParts = append(valueParts, "NULL")
303-
}
254+
kind3 = 3
255+
correlation = fmt.Sprintf("{%v}", *s.Correlation)
304256
}
305257

306-
insertSQL := `INSERT INTO pg_statistic (
258+
const insertSQL = `INSERT INTO pg_statistic (
307259
starelid, staattnum, stainherit, stanullfrac, stawidth, stadistinct,
308-
stakind1, staop1, stanumbers1, stavalues1,
309-
stakind2, staop2, stanumbers2, stavalues2,
310-
stakind3, staop3, stanumbers3, stavalues3,
311-
stakind4, staop4, stanumbers4, stavalues4,
312-
stakind5, staop5, stanumbers5, stavalues5
313-
) VALUES (` + strings.Join(valueParts, ", ") + ")"
314-
315-
_, err = tx.Exec(ctx, insertSQL, args...)
316-
if err != nil {
260+
stakind1, staop1, stacoll1, stanumbers1, stavalues1,
261+
stakind2, staop2, stacoll2, stanumbers2, stavalues2,
262+
stakind3, staop3, stacoll3, stanumbers3, stavalues3,
263+
stakind4, staop4, stacoll4, stanumbers4, stavalues4,
264+
stakind5, staop5, stacoll5, stanumbers5, stavalues5
265+
) VALUES ($1, $2, false, $3, 0, $4,
266+
0, 0, 0, NULL, NULL,
267+
0, 0, 0, NULL, NULL,
268+
$5, 0, 0, $6::real[], NULL,
269+
0, 0, 0, NULL, NULL,
270+
0, 0, 0, NULL, NULL)`
271+
272+
if _, err := tx.Exec(ctx, insertSQL, cm.relOID, cm.attNum, nullFrac, nDistinct, kind3, correlation); err != nil {
317273
return fmt.Errorf("insert pg_statistic: %w", err)
318274
}
319-
320275
return nil
321276
}
322277

internal/schema/sql/inject.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ SELECT a.attname,
1818

1919
-- name: restore-relation-stats-pg18
2020
SELECT pg_restore_relation_stats(
21-
'version', $1::int, 'schemaname', $2::name, 'relname', $3::name,
21+
'version', $1::int, 'schemaname', $2::text, 'relname', $3::text,
2222
'relpages', $4::integer, 'reltuples', $5::real
2323
)
2424

0 commit comments

Comments
 (0)