Coverage Report

Created: 2026-08-13 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/access/table/tableamapi.c
Line
Count
Source
1
/*----------------------------------------------------------------------
2
 *
3
 * tableamapi.c
4
 *    Support routines for API for Postgres table access methods
5
 *
6
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 * src/backend/access/table/tableamapi.c
10
 *----------------------------------------------------------------------
11
 */
12
#include "postgres.h"
13
14
#include "access/tableam.h"
15
#include "access/xact.h"
16
#include "commands/defrem.h"
17
#include "miscadmin.h"
18
#include "utils/guc_hooks.h"
19
20
21
/*
22
 * GetTableAmRoutine
23
 *    Call the specified access method handler routine to get its
24
 *    TableAmRoutine struct, which we expect to be statically allocated.
25
 */
26
const TableAmRoutine *
27
GetTableAmRoutine(Oid amhandler)
28
0
{
29
0
  Datum   datum;
30
0
  const TableAmRoutine *routine;
31
32
0
  datum = OidFunctionCall0(amhandler);
33
0
  routine = (const TableAmRoutine *) DatumGetPointer(datum);
34
35
0
  if (routine == NULL || !IsA(routine, TableAmRoutine))
36
0
    elog(ERROR, "table access method handler %u did not return a TableAmRoutine struct",
37
0
       amhandler);
38
39
  /*
40
   * Assert that all required callbacks are present. That makes it a bit
41
   * easier to keep AMs up to date, e.g. when forward porting them to a new
42
   * major version.
43
   */
44
0
  Assert(routine->scan_begin != NULL);
45
0
  Assert(routine->scan_end != NULL);
46
0
  Assert(routine->scan_rescan != NULL);
47
0
  Assert(routine->scan_getnextslot != NULL);
48
49
0
  Assert(routine->parallelscan_estimate != NULL);
50
0
  Assert(routine->parallelscan_initialize != NULL);
51
0
  Assert(routine->parallelscan_reinitialize != NULL);
52
53
0
  Assert(routine->index_fetch_begin != NULL);
54
0
  Assert(routine->index_fetch_reset != NULL);
55
0
  Assert(routine->index_fetch_end != NULL);
56
0
  Assert(routine->index_fetch_tuple != NULL);
57
58
0
  Assert(routine->tuple_fetch_row_version != NULL);
59
0
  Assert(routine->tuple_tid_valid != NULL);
60
0
  Assert(routine->tuple_get_latest_tid != NULL);
61
0
  Assert(routine->tuple_satisfies_snapshot != NULL);
62
0
  Assert(routine->index_delete_tuples != NULL);
63
64
0
  Assert(routine->tuple_insert != NULL);
65
66
  /*
67
   * Could be made optional, but would require throwing error during
68
   * parse-analysis.
69
   */
70
0
  Assert(routine->tuple_insert_speculative != NULL);
71
0
  Assert(routine->tuple_complete_speculative != NULL);
72
73
0
  Assert(routine->multi_insert != NULL);
74
0
  Assert(routine->tuple_delete != NULL);
75
0
  Assert(routine->tuple_update != NULL);
76
0
  Assert(routine->tuple_lock != NULL);
77
78
0
  Assert(routine->relation_set_new_filelocator != NULL);
79
0
  Assert(routine->relation_nontransactional_truncate != NULL);
80
0
  Assert(routine->relation_copy_data != NULL);
81
0
  Assert(routine->relation_copy_for_cluster != NULL);
82
0
  Assert(routine->relation_vacuum != NULL);
83
0
  Assert(routine->scan_analyze_next_block != NULL);
84
0
  Assert(routine->scan_analyze_next_tuple != NULL);
85
0
  Assert(routine->index_build_range_scan != NULL);
86
0
  Assert(routine->index_validate_scan != NULL);
87
88
0
  Assert(routine->relation_size != NULL);
89
0
  Assert(routine->relation_needs_toast_table != NULL);
90
91
0
  Assert(routine->relation_estimate_size != NULL);
92
93
0
  Assert(routine->scan_sample_next_block != NULL);
94
0
  Assert(routine->scan_sample_next_tuple != NULL);
95
96
0
  return routine;
97
0
}
98
99
/* check_hook: validate new default_table_access_method */
100
bool
101
check_default_table_access_method(char **newval, void **extra, GucSource source)
102
2
{
103
2
  if (**newval == '\0')
104
0
  {
105
0
    GUC_check_errdetail("\"%s\" cannot be empty.",
106
0
              "default_table_access_method");
107
0
    return false;
108
0
  }
109
110
2
  if (strlen(*newval) >= NAMEDATALEN)
111
0
  {
112
0
    GUC_check_errdetail("\"%s\" is too long (maximum %d characters).",
113
0
              "default_table_access_method", NAMEDATALEN - 1);
114
0
    return false;
115
0
  }
116
117
  /*
118
   * If we aren't inside a transaction, or not connected to a database, we
119
   * cannot do the catalog access necessary to verify the method.  Must
120
   * accept the value on faith.
121
   */
122
2
  if (IsTransactionState() && MyDatabaseId != InvalidOid)
123
0
  {
124
0
    if (!OidIsValid(get_table_am_oid(*newval, true)))
125
0
    {
126
      /*
127
       * When source == PGC_S_TEST, don't throw a hard error for a
128
       * nonexistent table access method, only a NOTICE. See comments in
129
       * guc.h.
130
       */
131
0
      if (source == PGC_S_TEST)
132
0
      {
133
0
        ereport(NOTICE,
134
0
            (errcode(ERRCODE_UNDEFINED_OBJECT),
135
0
             errmsg("table access method \"%s\" does not exist",
136
0
                *newval)));
137
0
      }
138
0
      else
139
0
      {
140
0
        GUC_check_errdetail("Table access method \"%s\" does not exist.",
141
0
                  *newval);
142
0
        return false;
143
0
      }
144
0
    }
145
0
  }
146
147
2
  return true;
148
2
}