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 * 35 1507002 : GetTableAmRoutine(Oid amhandler) 36 : { 37 : Datum datum; 38 : const TableAmRoutine *routine; 39 : 40 1507002 : datum = OidFunctionCall0(amhandler); 41 1507002 : routine = (TableAmRoutine *) DatumGetPointer(datum); 42 : 43 1507002 : if (routine == NULL || !IsA(routine, TableAmRoutine)) 44 0 : elog(ERROR, "table access method handler %u did not return a TableAmRoutine struct", 45 : 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 : */ 52 : Assert(routine->scan_begin != NULL); 53 : Assert(routine->scan_end != NULL); 54 : Assert(routine->scan_rescan != NULL); 55 : Assert(routine->scan_getnextslot != NULL); 56 : 57 : Assert(routine->parallelscan_estimate != NULL); 58 : Assert(routine->parallelscan_initialize != NULL); 59 : Assert(routine->parallelscan_reinitialize != NULL); 60 : 61 : Assert(routine->index_fetch_begin != NULL); 62 : Assert(routine->index_fetch_reset != NULL); 63 : Assert(routine->index_fetch_end != NULL); 64 : Assert(routine->index_fetch_tuple != NULL); 65 : 66 : Assert(routine->tuple_fetch_row_version != NULL); 67 : Assert(routine->tuple_tid_valid != NULL); 68 : Assert(routine->tuple_get_latest_tid != NULL); 69 : Assert(routine->tuple_satisfies_snapshot != NULL); 70 : Assert(routine->index_delete_tuples != NULL); 71 : 72 : Assert(routine->tuple_insert != NULL); 73 : 74 : /* 75 : * Could be made optional, but would require throwing error during 76 : * parse-analysis. 77 : */ 78 : Assert(routine->tuple_insert_speculative != NULL); 79 : Assert(routine->tuple_complete_speculative != NULL); 80 : 81 : Assert(routine->multi_insert != NULL); 82 : Assert(routine->tuple_delete != NULL); 83 : Assert(routine->tuple_update != NULL); 84 : Assert(routine->tuple_lock != NULL); 85 : 86 : Assert(routine->relation_set_new_filelocator != NULL); 87 : Assert(routine->relation_nontransactional_truncate != NULL); 88 : Assert(routine->relation_copy_data != NULL); 89 : Assert(routine->relation_copy_for_cluster != NULL); 90 : Assert(routine->relation_vacuum != NULL); 91 : Assert(routine->scan_analyze_next_block != NULL); 92 : Assert(routine->scan_analyze_next_tuple != NULL); 93 : Assert(routine->index_build_range_scan != NULL); 94 : Assert(routine->index_validate_scan != NULL); 95 : 96 : Assert(routine->relation_size != NULL); 97 : Assert(routine->relation_needs_toast_table != NULL); 98 : 99 : Assert(routine->relation_estimate_size != NULL); 100 : 101 : /* optional, but one callback implies presence of the other */ 102 : Assert((routine->scan_bitmap_next_block == NULL) == 103 : (routine->scan_bitmap_next_tuple == NULL)); 104 : Assert(routine->scan_sample_next_block != NULL); 105 : Assert(routine->scan_sample_next_tuple != NULL); 106 : 107 1507002 : return routine; 108 : } 109 : 110 : /* check_hook: validate new default_table_access_method */ 111 : bool 112 1628 : check_default_table_access_method(char **newval, void **extra, GucSource source) 113 : { 114 1628 : if (**newval == '\0') 115 : { 116 6 : GUC_check_errdetail("%s cannot be empty.", 117 : "default_table_access_method"); 118 6 : return false; 119 : } 120 : 121 1622 : if (strlen(*newval) >= NAMEDATALEN) 122 : { 123 0 : GUC_check_errdetail("%s is too long (maximum %d characters).", 124 : "default_table_access_method", NAMEDATALEN - 1); 125 0 : return false; 126 : } 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 : */ 133 1622 : if (IsTransactionState() && MyDatabaseId != InvalidOid) 134 : { 135 56 : if (!OidIsValid(get_table_am_oid(*newval, true))) 136 : { 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 : */ 142 6 : if (source == PGC_S_TEST) 143 : { 144 0 : ereport(NOTICE, 145 : (errcode(ERRCODE_UNDEFINED_OBJECT), 146 : errmsg("table access method \"%s\" does not exist", 147 : *newval))); 148 : } 149 : else 150 : { 151 6 : GUC_check_errdetail("Table access method \"%s\" does not exist.", 152 : *newval); 153 6 : return false; 154 : } 155 : } 156 : } 157 : 158 1610 : return true; 159 : }