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