Branch data 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 : 99347 : GetTableAmRoutine(Oid amhandler)
28 : : {
29 : 99347 : Datum datum;
30 : 99347 : const TableAmRoutine *routine;
31 : :
32 : 99347 : datum = OidFunctionCall0(amhandler);
33 : 99347 : routine = (const TableAmRoutine *) DatumGetPointer(datum);
34 : :
35 [ + - ]: 99347 : 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 [ + - ]: 99347 : Assert(routine->scan_begin != NULL);
45 [ + - ]: 99347 : Assert(routine->scan_end != NULL);
46 [ + - ]: 99347 : Assert(routine->scan_rescan != NULL);
47 [ + - ]: 99347 : Assert(routine->scan_getnextslot != NULL);
48 : :
49 [ + - ]: 99347 : Assert(routine->parallelscan_estimate != NULL);
50 [ + - ]: 99347 : Assert(routine->parallelscan_initialize != NULL);
51 [ + - ]: 99347 : Assert(routine->parallelscan_reinitialize != NULL);
52 : :
53 [ + - ]: 99347 : Assert(routine->index_fetch_begin != NULL);
54 [ + - ]: 99347 : Assert(routine->index_fetch_reset != NULL);
55 [ + - ]: 99347 : Assert(routine->index_fetch_end != NULL);
56 [ + - ]: 99347 : Assert(routine->index_fetch_tuple != NULL);
57 : :
58 [ + - ]: 99347 : Assert(routine->tuple_fetch_row_version != NULL);
59 [ + - ]: 99347 : Assert(routine->tuple_tid_valid != NULL);
60 [ + - ]: 99347 : Assert(routine->tuple_get_latest_tid != NULL);
61 [ + - ]: 99347 : Assert(routine->tuple_satisfies_snapshot != NULL);
62 [ + - ]: 99347 : Assert(routine->index_delete_tuples != NULL);
63 : :
64 [ + - ]: 99347 : Assert(routine->tuple_insert != NULL);
65 : :
66 : : /*
67 : : * Could be made optional, but would require throwing error during
68 : : * parse-analysis.
69 : : */
70 [ + - ]: 99347 : Assert(routine->tuple_insert_speculative != NULL);
71 [ + - ]: 99347 : Assert(routine->tuple_complete_speculative != NULL);
72 : :
73 [ + - ]: 99347 : Assert(routine->multi_insert != NULL);
74 [ + - ]: 99347 : Assert(routine->tuple_delete != NULL);
75 [ + - ]: 99347 : Assert(routine->tuple_update != NULL);
76 [ + - ]: 99347 : Assert(routine->tuple_lock != NULL);
77 : :
78 [ + - ]: 99347 : Assert(routine->relation_set_new_filelocator != NULL);
79 [ + - ]: 99347 : Assert(routine->relation_nontransactional_truncate != NULL);
80 [ + - ]: 99347 : Assert(routine->relation_copy_data != NULL);
81 [ + - ]: 99347 : Assert(routine->relation_copy_for_cluster != NULL);
82 [ + - ]: 99347 : Assert(routine->relation_vacuum != NULL);
83 [ + - ]: 99347 : Assert(routine->scan_analyze_next_block != NULL);
84 [ + - ]: 99347 : Assert(routine->scan_analyze_next_tuple != NULL);
85 [ + - ]: 99347 : Assert(routine->index_build_range_scan != NULL);
86 [ + - ]: 99347 : Assert(routine->index_validate_scan != NULL);
87 : :
88 [ + - ]: 99347 : Assert(routine->relation_size != NULL);
89 [ + - ]: 99347 : Assert(routine->relation_needs_toast_table != NULL);
90 : :
91 [ + - ]: 99347 : Assert(routine->relation_estimate_size != NULL);
92 : :
93 [ + - ]: 99347 : Assert(routine->scan_sample_next_block != NULL);
94 [ + - ]: 99347 : Assert(routine->scan_sample_next_tuple != NULL);
95 : :
96 : 198694 : return routine;
97 : 99347 : }
98 : :
99 : : /* check_hook: validate new default_table_access_method */
100 : : bool
101 : 19 : check_default_table_access_method(char **newval, void **extra, GucSource source)
102 : : {
103 [ + + ]: 19 : if (**newval == '\0')
104 : : {
105 : 1 : GUC_check_errdetail("\"%s\" cannot be empty.",
106 : : "default_table_access_method");
107 : 1 : return false;
108 : : }
109 : :
110 [ - + ]: 18 : 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 [ + + + + ]: 18 : if (IsTransactionState() && MyDatabaseId != InvalidOid)
123 : : {
124 [ + + ]: 12 : 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 [ - + ]: 1 : 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 : 0 : }
138 : : else
139 : : {
140 : 2 : GUC_check_errdetail("Table access method \"%s\" does not exist.",
141 : 1 : *newval);
142 : 1 : return false;
143 : : }
144 : 0 : }
145 : 11 : }
146 : :
147 : 17 : return true;
148 : 19 : }
|