Age Owner Branch data 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-2025, 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 will be palloc'd in the caller's
25 : : * memory context.
26 : : */
27 : : const TableAmRoutine *
2376 andres@anarazel.de 28 :CBC 993672 : GetTableAmRoutine(Oid amhandler)
29 : : {
30 : : Datum datum;
31 : : const TableAmRoutine *routine;
32 : :
33 : 993672 : datum = OidFunctionCall0(amhandler);
34 : 993672 : routine = (TableAmRoutine *) DatumGetPointer(datum);
35 : :
36 [ + - - + ]: 993672 : if (routine == NULL || !IsA(routine, TableAmRoutine))
2347 andres@anarazel.de 37 [ # # ]:UBC 0 : elog(ERROR, "table access method handler %u did not return a TableAmRoutine struct",
38 : : amhandler);
39 : :
40 : : /*
41 : : * Assert that all required callbacks are present. That makes it a bit
42 : : * easier to keep AMs up to date, e.g. when forward porting them to a new
43 : : * major version.
44 : : */
2371 andres@anarazel.de 45 [ - + ]:CBC 993672 : Assert(routine->scan_begin != NULL);
46 [ - + ]: 993672 : Assert(routine->scan_end != NULL);
47 [ - + ]: 993672 : Assert(routine->scan_rescan != NULL);
2254 akapila@postgresql.o 48 [ - + ]: 993672 : Assert(routine->scan_getnextslot != NULL);
49 : :
2371 andres@anarazel.de 50 [ - + ]: 993672 : Assert(routine->parallelscan_estimate != NULL);
51 [ - + ]: 993672 : Assert(routine->parallelscan_initialize != NULL);
52 [ - + ]: 993672 : Assert(routine->parallelscan_reinitialize != NULL);
53 : :
54 [ - + ]: 993672 : Assert(routine->index_fetch_begin != NULL);
55 [ - + ]: 993672 : Assert(routine->index_fetch_reset != NULL);
56 [ - + ]: 993672 : Assert(routine->index_fetch_end != NULL);
57 [ - + ]: 993672 : Assert(routine->index_fetch_tuple != NULL);
58 : :
2357 59 [ - + ]: 993672 : Assert(routine->tuple_fetch_row_version != NULL);
2254 akapila@postgresql.o 60 [ - + ]: 993672 : Assert(routine->tuple_tid_valid != NULL);
61 [ - + ]: 993672 : Assert(routine->tuple_get_latest_tid != NULL);
2371 andres@anarazel.de 62 [ - + ]: 993672 : Assert(routine->tuple_satisfies_snapshot != NULL);
1697 pg@bowt.ie 63 [ - + ]: 993672 : Assert(routine->index_delete_tuples != NULL);
64 : :
2359 andres@anarazel.de 65 [ - + ]: 993672 : Assert(routine->tuple_insert != NULL);
66 : :
67 : : /*
68 : : * Could be made optional, but would require throwing error during
69 : : * parse-analysis.
70 : : */
71 [ - + ]: 993672 : Assert(routine->tuple_insert_speculative != NULL);
72 [ - + ]: 993672 : Assert(routine->tuple_complete_speculative != NULL);
73 : :
2347 74 [ - + ]: 993672 : Assert(routine->multi_insert != NULL);
2359 75 [ - + ]: 993672 : Assert(routine->tuple_delete != NULL);
76 [ - + ]: 993672 : Assert(routine->tuple_update != NULL);
77 [ - + ]: 993672 : Assert(routine->tuple_lock != NULL);
78 : :
1158 rhaas@postgresql.org 79 [ - + ]: 993672 : Assert(routine->relation_set_new_filelocator != NULL);
2352 andres@anarazel.de 80 [ - + ]: 993672 : Assert(routine->relation_nontransactional_truncate != NULL);
81 [ - + ]: 993672 : Assert(routine->relation_copy_data != NULL);
82 [ - + ]: 993672 : Assert(routine->relation_copy_for_cluster != NULL);
83 [ - + ]: 993672 : Assert(routine->relation_vacuum != NULL);
508 akorotkov@postgresql 84 [ - + ]: 993672 : Assert(routine->scan_analyze_next_block != NULL);
85 [ - + ]: 993672 : Assert(routine->scan_analyze_next_tuple != NULL);
2352 andres@anarazel.de 86 [ - + ]: 993672 : Assert(routine->index_build_range_scan != NULL);
87 [ - + ]: 993672 : Assert(routine->index_validate_scan != NULL);
88 : :
2304 89 [ - + ]: 993672 : Assert(routine->relation_size != NULL);
2254 akapila@postgresql.o 90 [ - + ]: 993672 : Assert(routine->relation_needs_toast_table != NULL);
91 : :
2352 andres@anarazel.de 92 [ - + ]: 993672 : Assert(routine->relation_estimate_size != NULL);
93 : :
94 [ - + ]: 993672 : Assert(routine->scan_sample_next_block != NULL);
95 [ - + ]: 993672 : Assert(routine->scan_sample_next_tuple != NULL);
96 : :
2376 97 : 993672 : return routine;
98 : : }
99 : :
100 : : /* check_hook: validate new default_table_access_method */
101 : : bool
102 : 1136 : check_default_table_access_method(char **newval, void **extra, GucSource source)
103 : : {
2347 104 [ + + ]: 1136 : if (**newval == '\0')
105 : : {
477 peter@eisentraut.org 106 : 3 : GUC_check_errdetail("\"%s\" cannot be empty.",
107 : : "default_table_access_method");
2347 andres@anarazel.de 108 : 3 : return false;
109 : : }
110 : :
111 [ - + ]: 1133 : if (strlen(*newval) >= NAMEDATALEN)
112 : : {
477 peter@eisentraut.org 113 :UBC 0 : GUC_check_errdetail("\"%s\" is too long (maximum %d characters).",
114 : : "default_table_access_method", NAMEDATALEN - 1);
2347 andres@anarazel.de 115 : 0 : return false;
116 : : }
117 : :
118 : : /*
119 : : * If we aren't inside a transaction, or not connected to a database, we
120 : : * cannot do the catalog access necessary to verify the method. Must
121 : : * accept the value on faith.
122 : : */
2280 andres@anarazel.de 123 [ + + + - ]:CBC 1133 : if (IsTransactionState() && MyDatabaseId != InvalidOid)
124 : : {
2347 125 [ + + ]: 66 : if (!OidIsValid(get_table_am_oid(*newval, true)))
126 : : {
127 : : /*
128 : : * When source == PGC_S_TEST, don't throw a hard error for a
129 : : * nonexistent table access method, only a NOTICE. See comments in
130 : : * guc.h.
131 : : */
2376 132 [ - + ]: 3 : if (source == PGC_S_TEST)
133 : : {
2376 andres@anarazel.de 134 [ # # ]:UBC 0 : ereport(NOTICE,
135 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
136 : : errmsg("table access method \"%s\" does not exist",
137 : : *newval)));
138 : : }
139 : : else
140 : : {
2376 andres@anarazel.de 141 :CBC 3 : GUC_check_errdetail("Table access method \"%s\" does not exist.",
142 : : *newval);
143 : 3 : return false;
144 : : }
145 : : }
146 : : }
147 : :
148 : 1127 : return true;
149 : : }
|