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-2024, 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 1959244 : GetTableAmRoutine(Oid amhandler) 29 : { 30 : Datum datum; 31 : const TableAmRoutine *routine; 32 : 33 1959244 : datum = OidFunctionCall0(amhandler); 34 1959244 : routine = (TableAmRoutine *) DatumGetPointer(datum); 35 : 36 1959244 : 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 : /* optional, but one callback implies presence of the other */ 95 : Assert((routine->scan_bitmap_next_block == NULL) == 96 : (routine->scan_bitmap_next_tuple == NULL)); 97 : Assert(routine->scan_sample_next_block != NULL); 98 : Assert(routine->scan_sample_next_tuple != NULL); 99 : 100 1959244 : return routine; 101 : } 102 : 103 : /* check_hook: validate new default_table_access_method */ 104 : bool 105 2080 : check_default_table_access_method(char **newval, void **extra, GucSource source) 106 : { 107 2080 : if (**newval == '\0') 108 : { 109 6 : GUC_check_errdetail("\"%s\" cannot be empty.", 110 : "default_table_access_method"); 111 6 : return false; 112 : } 113 : 114 2074 : if (strlen(*newval) >= NAMEDATALEN) 115 : { 116 0 : GUC_check_errdetail("\"%s\" is too long (maximum %d characters).", 117 : "default_table_access_method", NAMEDATALEN - 1); 118 0 : return false; 119 : } 120 : 121 : /* 122 : * If we aren't inside a transaction, or not connected to a database, we 123 : * cannot do the catalog access necessary to verify the method. Must 124 : * accept the value on faith. 125 : */ 126 2074 : if (IsTransactionState() && MyDatabaseId != InvalidOid) 127 : { 128 108 : if (!OidIsValid(get_table_am_oid(*newval, true))) 129 : { 130 : /* 131 : * When source == PGC_S_TEST, don't throw a hard error for a 132 : * nonexistent table access method, only a NOTICE. See comments in 133 : * guc.h. 134 : */ 135 6 : if (source == PGC_S_TEST) 136 : { 137 0 : ereport(NOTICE, 138 : (errcode(ERRCODE_UNDEFINED_OBJECT), 139 : errmsg("table access method \"%s\" does not exist", 140 : *newval))); 141 : } 142 : else 143 : { 144 6 : GUC_check_errdetail("Table access method \"%s\" does not exist.", 145 : *newval); 146 6 : return false; 147 : } 148 : } 149 : } 150 : 151 2062 : return true; 152 : }