pgx_catalog_test.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package pgserver
  2. import (
  3. "context"
  4. "testing"
  5. )
  6. // A stock pgx connection introspects the catalog with its normal
  7. // Parse/Bind/Execute path. This covers the real driver reading oid/name/regclass
  8. // columns and issuing SET during a session.
  9. func TestPGXCatalogIntrospection(t *testing.T) {
  10. conn := connectPGX(t)
  11. ctx := context.Background()
  12. for _, sql := range []string{
  13. `CREATE TABLE catalog_parent (id INTEGER PRIMARY KEY, label TEXT NOT NULL UNIQUE)`,
  14. `CREATE TABLE catalog_child (id INTEGER PRIMARY KEY, parent_id INTEGER NOT NULL, note TEXT DEFAULT 'n', CONSTRAINT fk_catalog_child FOREIGN KEY (parent_id) REFERENCES catalog_parent(id))`,
  15. `CREATE INDEX idx_catalog_child_note ON catalog_child (note)`,
  16. } {
  17. if _, err := conn.Exec(ctx, sql); err != nil {
  18. t.Fatalf("%s: %v", sql, err)
  19. }
  20. }
  21. var (
  22. oid uint32
  23. relname string
  24. relkind string
  25. )
  26. err := conn.QueryRow(ctx, `
  27. SELECT c.oid, c.relname, c.relkind
  28. FROM pg_catalog.pg_class c
  29. WHERE c.relname = 'catalog_child'`).Scan(&oid, &relname, &relkind)
  30. if err != nil {
  31. t.Fatalf("pg_class scan: %v", err)
  32. }
  33. if oid == 0 || relname != "catalog_child" || relkind != "r" {
  34. t.Fatalf("pg_class = %d %q %q", oid, relname, relkind)
  35. }
  36. rows, err := conn.Query(ctx, `
  37. SELECT n.nspname, a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod)
  38. FROM pg_catalog.pg_class c
  39. JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
  40. JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
  41. WHERE c.relname = 'catalog_child' AND a.attnum > 0
  42. ORDER BY a.attnum`)
  43. if err != nil {
  44. t.Fatalf("catalog join: %v", err)
  45. }
  46. defer rows.Close()
  47. var columns []string
  48. for rows.Next() {
  49. var schema, column, typ string
  50. if err := rows.Scan(&schema, &column, &typ); err != nil {
  51. t.Fatalf("scan: %v", err)
  52. }
  53. if schema != "public" {
  54. t.Fatalf("schema = %q", schema)
  55. }
  56. columns = append(columns, column+":"+typ)
  57. }
  58. if err := rows.Err(); err != nil {
  59. t.Fatalf("rows: %v", err)
  60. }
  61. want := []string{"id:integer", "parent_id:integer", "note:text"}
  62. if len(columns) != len(want) {
  63. t.Fatalf("columns = %v, want %v", columns, want)
  64. }
  65. for i := range want {
  66. if columns[i] != want[i] {
  67. t.Fatalf("columns = %v, want %v", columns, want)
  68. }
  69. }
  70. var (
  71. tableName string
  72. columnName string
  73. dataType string
  74. isNullable string
  75. )
  76. err = conn.QueryRow(ctx, `
  77. SELECT table_name, column_name, data_type, is_nullable
  78. FROM information_schema.columns
  79. WHERE table_name = 'catalog_child' AND column_name = 'note'`).
  80. Scan(&tableName, &columnName, &dataType, &isNullable)
  81. if err != nil {
  82. t.Fatalf("information_schema scan: %v", err)
  83. }
  84. if tableName != "catalog_child" || columnName != "note" || dataType != "text" || isNullable != "YES" {
  85. t.Fatalf("information_schema row = %q %q %q %q", tableName, columnName, dataType, isNullable)
  86. }
  87. if _, err := conn.Exec(ctx, "SET search_path TO public"); err != nil {
  88. t.Fatalf("SET search_path: %v", err)
  89. }
  90. var searchPath string
  91. if err := conn.QueryRow(ctx, "SHOW search_path").Scan(&searchPath); err != nil {
  92. t.Fatalf("SHOW search_path: %v", err)
  93. }
  94. if searchPath != "public" {
  95. t.Fatalf("search_path = %q", searchPath)
  96. }
  97. var regclassRows int
  98. if err := conn.QueryRow(ctx, `
  99. SELECT count(*) FROM pg_catalog.pg_constraint
  100. WHERE conrelid = 'catalog_child'::regclass AND contype = 'f'`).Scan(&regclassRows); err != nil {
  101. t.Fatalf("regclass constraint query: %v", err)
  102. }
  103. if regclassRows != 1 {
  104. t.Fatalf("foreign key constraint count = %d, want 1", regclassRows)
  105. }
  106. }