TLA 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-2023, 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/heapam.h"
15 : #include "access/htup_details.h"
16 : #include "access/tableam.h"
17 : #include "access/xact.h"
18 : #include "catalog/pg_am.h"
19 : #include "catalog/pg_proc.h"
20 : #include "commands/defrem.h"
21 : #include "miscadmin.h"
22 : #include "utils/fmgroids.h"
23 : #include "utils/guc_hooks.h"
24 : #include "utils/memutils.h"
25 : #include "utils/syscache.h"
26 :
27 :
28 : /*
29 : * GetTableAmRoutine
30 : * Call the specified access method handler routine to get its
31 : * TableAmRoutine struct, which will be palloc'd in the caller's
32 : * memory context.
33 : */
34 : const TableAmRoutine *
35 GIC 881910 : GetTableAmRoutine(Oid amhandler)
36 ECB : {
37 : Datum datum;
38 : const TableAmRoutine *routine;
39 :
40 GIC 881910 : datum = OidFunctionCall0(amhandler);
41 CBC 881910 : routine = (TableAmRoutine *) DatumGetPointer(datum);
42 ECB :
43 GIC 881910 : if (routine == NULL || !IsA(routine, TableAmRoutine))
44 LBC 0 : elog(ERROR, "table access method handler %u did not return a TableAmRoutine struct",
45 EUB : amhandler);
46 :
47 : /*
48 : * Assert that all required callbacks are present. That makes it a bit
49 : * easier to keep AMs up to date, e.g. when forward porting them to a new
50 : * major version.
51 : */
52 GIC 881910 : Assert(routine->scan_begin != NULL);
53 CBC 881910 : Assert(routine->scan_end != NULL);
54 881910 : Assert(routine->scan_rescan != NULL);
55 881910 : Assert(routine->scan_getnextslot != NULL);
56 ECB :
57 GIC 881910 : Assert(routine->parallelscan_estimate != NULL);
58 CBC 881910 : Assert(routine->parallelscan_initialize != NULL);
59 881910 : Assert(routine->parallelscan_reinitialize != NULL);
60 ECB :
61 GIC 881910 : Assert(routine->index_fetch_begin != NULL);
62 CBC 881910 : Assert(routine->index_fetch_reset != NULL);
63 881910 : Assert(routine->index_fetch_end != NULL);
64 881910 : Assert(routine->index_fetch_tuple != NULL);
65 ECB :
66 GIC 881910 : Assert(routine->tuple_fetch_row_version != NULL);
67 CBC 881910 : Assert(routine->tuple_tid_valid != NULL);
68 881910 : Assert(routine->tuple_get_latest_tid != NULL);
69 881910 : Assert(routine->tuple_satisfies_snapshot != NULL);
70 881910 : Assert(routine->index_delete_tuples != NULL);
71 ECB :
72 GIC 881910 : Assert(routine->tuple_insert != NULL);
73 ECB :
74 : /*
75 : * Could be made optional, but would require throwing error during
76 : * parse-analysis.
77 : */
78 GIC 881910 : Assert(routine->tuple_insert_speculative != NULL);
79 CBC 881910 : Assert(routine->tuple_complete_speculative != NULL);
80 ECB :
81 GIC 881910 : Assert(routine->multi_insert != NULL);
82 CBC 881910 : Assert(routine->tuple_delete != NULL);
83 881910 : Assert(routine->tuple_update != NULL);
84 881910 : Assert(routine->tuple_lock != NULL);
85 ECB :
86 GNC 881910 : Assert(routine->relation_set_new_filelocator != NULL);
87 CBC 881910 : Assert(routine->relation_nontransactional_truncate != NULL);
88 881910 : Assert(routine->relation_copy_data != NULL);
89 881910 : Assert(routine->relation_copy_for_cluster != NULL);
90 881910 : Assert(routine->relation_vacuum != NULL);
91 881910 : Assert(routine->scan_analyze_next_block != NULL);
92 881910 : Assert(routine->scan_analyze_next_tuple != NULL);
93 881910 : Assert(routine->index_build_range_scan != NULL);
94 881910 : Assert(routine->index_validate_scan != NULL);
95 ECB :
96 GIC 881910 : Assert(routine->relation_size != NULL);
97 CBC 881910 : Assert(routine->relation_needs_toast_table != NULL);
98 ECB :
99 GIC 881910 : Assert(routine->relation_estimate_size != NULL);
100 ECB :
101 : /* optional, but one callback implies presence of the other */
102 GIC 881910 : Assert((routine->scan_bitmap_next_block == NULL) ==
103 ECB : (routine->scan_bitmap_next_tuple == NULL));
104 GIC 881910 : Assert(routine->scan_sample_next_block != NULL);
105 CBC 881910 : Assert(routine->scan_sample_next_tuple != NULL);
106 ECB :
107 GIC 881910 : return routine;
108 ECB : }
109 :
110 : /* check_hook: validate new default_table_access_method */
111 : bool
112 GIC 1888 : check_default_table_access_method(char **newval, void **extra, GucSource source)
113 ECB : {
114 GIC 1888 : if (**newval == '\0')
115 ECB : {
116 GIC 3 : GUC_check_errdetail("%s cannot be empty.",
117 ECB : "default_table_access_method");
118 GIC 3 : return false;
119 ECB : }
120 :
121 GIC 1885 : if (strlen(*newval) >= NAMEDATALEN)
122 ECB : {
123 UIC 0 : GUC_check_errdetail("%s is too long (maximum %d characters).",
124 EUB : "default_table_access_method", NAMEDATALEN - 1);
125 UIC 0 : return false;
126 EUB : }
127 :
128 : /*
129 : * If we aren't inside a transaction, or not connected to a database, we
130 : * cannot do the catalog access necessary to verify the method. Must
131 : * accept the value on faith.
132 : */
133 GIC 1885 : if (IsTransactionState() && MyDatabaseId != InvalidOid)
134 ECB : {
135 GIC 28 : if (!OidIsValid(get_table_am_oid(*newval, true)))
136 ECB : {
137 : /*
138 : * When source == PGC_S_TEST, don't throw a hard error for a
139 : * nonexistent table access method, only a NOTICE. See comments in
140 : * guc.h.
141 : */
142 GIC 3 : if (source == PGC_S_TEST)
143 ECB : {
144 UIC 0 : ereport(NOTICE,
145 EUB : (errcode(ERRCODE_UNDEFINED_OBJECT),
146 : errmsg("table access method \"%s\" does not exist",
147 : *newval)));
148 : }
149 : else
150 : {
151 GIC 3 : GUC_check_errdetail("Table access method \"%s\" does not exist.",
152 ECB : *newval);
153 GIC 3 : return false;
154 ECB : }
155 : }
156 : }
157 :
158 GIC 1879 : return true;
159 ECB : }
|