Age Owner 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 *
1495 andres 35 GIC 881910 : GetTableAmRoutine(Oid amhandler)
1495 andres 36 ECB : {
37 : Datum datum;
38 : const TableAmRoutine *routine;
39 :
1495 andres 40 GIC 881910 : datum = OidFunctionCall0(amhandler);
1495 andres 41 CBC 881910 : routine = (TableAmRoutine *) DatumGetPointer(datum);
1495 andres 42 ECB :
1495 andres 43 GIC 881910 : if (routine == NULL || !IsA(routine, TableAmRoutine))
1466 andres 44 LBC 0 : elog(ERROR, "table access method handler %u did not return a TableAmRoutine struct",
1495 andres 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 : */
1490 andres 52 GIC 881910 : Assert(routine->scan_begin != NULL);
1490 andres 53 CBC 881910 : Assert(routine->scan_end != NULL);
54 881910 : Assert(routine->scan_rescan != NULL);
1373 akapila 55 881910 : Assert(routine->scan_getnextslot != NULL);
1490 andres 56 ECB :
1490 andres 57 GIC 881910 : Assert(routine->parallelscan_estimate != NULL);
1490 andres 58 CBC 881910 : Assert(routine->parallelscan_initialize != NULL);
59 881910 : Assert(routine->parallelscan_reinitialize != NULL);
1490 andres 60 ECB :
1490 andres 61 GIC 881910 : Assert(routine->index_fetch_begin != NULL);
1490 andres 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);
1490 andres 65 ECB :
1476 andres 66 GIC 881910 : Assert(routine->tuple_fetch_row_version != NULL);
1373 akapila 67 CBC 881910 : Assert(routine->tuple_tid_valid != NULL);
68 881910 : Assert(routine->tuple_get_latest_tid != NULL);
1490 andres 69 881910 : Assert(routine->tuple_satisfies_snapshot != NULL);
816 pg 70 881910 : Assert(routine->index_delete_tuples != NULL);
1490 andres 71 ECB :
1478 andres 72 GIC 881910 : Assert(routine->tuple_insert != NULL);
1478 andres 73 ECB :
74 : /*
75 : * Could be made optional, but would require throwing error during
76 : * parse-analysis.
77 : */
1478 andres 78 GIC 881910 : Assert(routine->tuple_insert_speculative != NULL);
1478 andres 79 CBC 881910 : Assert(routine->tuple_complete_speculative != NULL);
1478 andres 80 ECB :
1466 andres 81 GIC 881910 : Assert(routine->multi_insert != NULL);
1478 andres 82 CBC 881910 : Assert(routine->tuple_delete != NULL);
83 881910 : Assert(routine->tuple_update != NULL);
84 881910 : Assert(routine->tuple_lock != NULL);
1478 andres 85 ECB :
277 rhaas 86 GNC 881910 : Assert(routine->relation_set_new_filelocator != NULL);
1471 andres 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);
1423 andres 95 ECB :
1423 andres 96 GIC 881910 : Assert(routine->relation_size != NULL);
1373 akapila 97 CBC 881910 : Assert(routine->relation_needs_toast_table != NULL);
1423 andres 98 ECB :
1471 andres 99 GIC 881910 : Assert(routine->relation_estimate_size != NULL);
1471 andres 100 ECB :
101 : /* optional, but one callback implies presence of the other */
1470 andres 102 GIC 881910 : Assert((routine->scan_bitmap_next_block == NULL) ==
1470 andres 103 ECB : (routine->scan_bitmap_next_tuple == NULL));
1471 andres 104 GIC 881910 : Assert(routine->scan_sample_next_block != NULL);
1471 andres 105 CBC 881910 : Assert(routine->scan_sample_next_tuple != NULL);
1471 andres 106 ECB :
1495 andres 107 GIC 881910 : return routine;
1495 andres 108 ECB : }
109 :
110 : /* check_hook: validate new default_table_access_method */
111 : bool
1495 andres 112 GIC 1888 : check_default_table_access_method(char **newval, void **extra, GucSource source)
1495 andres 113 ECB : {
1466 andres 114 GIC 1888 : if (**newval == '\0')
1466 andres 115 ECB : {
1403 alvherre 116 GIC 3 : GUC_check_errdetail("%s cannot be empty.",
1403 alvherre 117 ECB : "default_table_access_method");
1466 andres 118 GIC 3 : return false;
1466 andres 119 ECB : }
120 :
1466 andres 121 GIC 1885 : if (strlen(*newval) >= NAMEDATALEN)
1466 andres 122 ECB : {
1440 alvherre 123 UIC 0 : GUC_check_errdetail("%s is too long (maximum %d characters).",
1440 alvherre 124 EUB : "default_table_access_method", NAMEDATALEN - 1);
1466 andres 125 UIC 0 : return false;
1466 andres 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 : */
1399 andres 133 GIC 1885 : if (IsTransactionState() && MyDatabaseId != InvalidOid)
1495 andres 134 ECB : {
1466 andres 135 GIC 28 : if (!OidIsValid(get_table_am_oid(*newval, true)))
1495 andres 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 : */
1495 andres 142 GIC 3 : if (source == PGC_S_TEST)
1495 andres 143 ECB : {
1495 andres 144 UIC 0 : ereport(NOTICE,
1495 andres 145 EUB : (errcode(ERRCODE_UNDEFINED_OBJECT),
146 : errmsg("table access method \"%s\" does not exist",
147 : *newval)));
148 : }
149 : else
150 : {
1495 andres 151 GIC 3 : GUC_check_errdetail("Table access method \"%s\" does not exist.",
1495 andres 152 ECB : *newval);
1495 andres 153 GIC 3 : return false;
1495 andres 154 ECB : }
155 : }
156 : }
157 :
1495 andres 158 GIC 1879 : return true;
1495 andres 159 ECB : }
|