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 2480240 : GetTableAmRoutine(Oid amhandler) 28 : { 29 : Datum datum; 30 : const TableAmRoutine *routine; 31 : 32 2480240 : datum = OidFunctionCall0(amhandler); 33 2480240 : routine = (const TableAmRoutine *) DatumGetPointer(datum); 34 : 35 2480240 : 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 2480240 : return routine; 97 : } 98 : 99 : /* check_hook: validate new default_table_access_method */ 100 : bool 101 2482 : check_default_table_access_method(char **newval, void **extra, GucSource source) 102 : { 103 2482 : if (**newval == '\0') 104 : { 105 6 : GUC_check_errdetail("\"%s\" cannot be empty.", 106 : "default_table_access_method"); 107 6 : return false; 108 : } 109 : 110 2476 : 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 2476 : if (IsTransactionState() && MyDatabaseId != InvalidOid) 123 : { 124 134 : 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 6 : 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 6 : GUC_check_errdetail("Table access method \"%s\" does not exist.", 141 : *newval); 142 6 : return false; 143 : } 144 : } 145 : } 146 : 147 2464 : return true; 148 : }