Line data Source code
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 1276595 : GetTableAmRoutine(Oid amhandler)
28 : {
29 : Datum datum;
30 : const TableAmRoutine *routine;
31 :
32 1276595 : datum = OidFunctionCall0(amhandler);
33 1276595 : routine = (const TableAmRoutine *) DatumGetPointer(datum);
34 :
35 1276595 : if (routine == NULL || !IsA(routine, TableAmRoutine))
36 0 : elog(ERROR, "table access method handler %u did not return a TableAmRoutine struct",
37 : 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 : Assert(routine->scan_begin != NULL);
45 : Assert(routine->scan_end != NULL);
46 : Assert(routine->scan_rescan != NULL);
47 : Assert(routine->scan_getnextslot != NULL);
48 :
49 : Assert(routine->parallelscan_estimate != NULL);
50 : Assert(routine->parallelscan_initialize != NULL);
51 : Assert(routine->parallelscan_reinitialize != NULL);
52 :
53 : Assert(routine->index_fetch_begin != NULL);
54 : Assert(routine->index_fetch_reset != NULL);
55 : Assert(routine->index_fetch_end != NULL);
56 : Assert(routine->index_fetch_tuple != NULL);
57 :
58 : Assert(routine->tuple_fetch_row_version != NULL);
59 : Assert(routine->tuple_tid_valid != NULL);
60 : Assert(routine->tuple_get_latest_tid != NULL);
61 : Assert(routine->tuple_satisfies_snapshot != NULL);
62 : Assert(routine->index_delete_tuples != NULL);
63 :
64 : Assert(routine->tuple_insert != NULL);
65 :
66 : /*
67 : * Could be made optional, but would require throwing error during
68 : * parse-analysis.
69 : */
70 : Assert(routine->tuple_insert_speculative != NULL);
71 : Assert(routine->tuple_complete_speculative != NULL);
72 :
73 : Assert(routine->multi_insert != NULL);
74 : Assert(routine->tuple_delete != NULL);
75 : Assert(routine->tuple_update != NULL);
76 : Assert(routine->tuple_lock != NULL);
77 :
78 : Assert(routine->relation_set_new_filelocator != NULL);
79 : Assert(routine->relation_nontransactional_truncate != NULL);
80 : Assert(routine->relation_copy_data != NULL);
81 : Assert(routine->relation_copy_for_cluster != NULL);
82 : Assert(routine->relation_vacuum != NULL);
83 : Assert(routine->scan_analyze_next_block != NULL);
84 : Assert(routine->scan_analyze_next_tuple != NULL);
85 : Assert(routine->index_build_range_scan != NULL);
86 : Assert(routine->index_validate_scan != NULL);
87 :
88 : Assert(routine->relation_size != NULL);
89 : Assert(routine->relation_needs_toast_table != NULL);
90 :
91 : Assert(routine->relation_estimate_size != NULL);
92 :
93 : Assert(routine->scan_sample_next_block != NULL);
94 : Assert(routine->scan_sample_next_tuple != NULL);
95 :
96 1276595 : return routine;
97 : }
98 :
99 : /* check_hook: validate new default_table_access_method */
100 : bool
101 1259 : check_default_table_access_method(char **newval, void **extra, GucSource source)
102 : {
103 1259 : if (**newval == '\0')
104 : {
105 3 : GUC_check_errdetail("\"%s\" cannot be empty.",
106 : "default_table_access_method");
107 3 : return false;
108 : }
109 :
110 1256 : if (strlen(*newval) >= NAMEDATALEN)
111 : {
112 0 : GUC_check_errdetail("\"%s\" is too long (maximum %d characters).",
113 : "default_table_access_method", NAMEDATALEN - 1);
114 0 : return false;
115 : }
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 1256 : if (IsTransactionState() && MyDatabaseId != InvalidOid)
123 : {
124 69 : if (!OidIsValid(get_table_am_oid(*newval, true)))
125 : {
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 3 : if (source == PGC_S_TEST)
132 : {
133 0 : ereport(NOTICE,
134 : (errcode(ERRCODE_UNDEFINED_OBJECT),
135 : errmsg("table access method \"%s\" does not exist",
136 : *newval)));
137 : }
138 : else
139 : {
140 3 : GUC_check_errdetail("Table access method \"%s\" does not exist.",
141 : *newval);
142 3 : return false;
143 : }
144 : }
145 : }
146 :
147 1250 : return true;
148 : }
|