-
Notifications
You must be signed in to change notification settings - Fork 171
Expand file tree
/
Copy pathrelations.cpp
More file actions
175 lines (145 loc) · 4.91 KB
/
relations.cpp
File metadata and controls
175 lines (145 loc) · 4.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include "pgduckdb/pg/relations.hpp"
#include "pgduckdb/pgduckdb_utils.hpp"
extern "C" {
#include "postgres.h"
#include "access/htup_details.h" // GETSTRUCT
#include "access/relation.h" // relation_open and relation_close
#include "catalog/namespace.h" // makeRangeVarFromNameList, RangeVarGetRelid
#include "optimizer/plancat.h" // estimate_rel_size
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/rls.h"
#include "utils/resowner.h" // CurrentResourceOwner and TopTransactionResourceOwner
#include "executor/tuptable.h" // TupIsNull
#include "utils/syscache.h" // RELOID
}
namespace pgduckdb {
#undef RelationGetDescr
#if PG_VERSION_NUM < 150000
// clang-format off
/*
* Relation kinds with a table access method (rd_tableam). Although sequences
* use the heap table AM, they are enough of a special case in most uses that
* they are not included here. Likewise, partitioned tables can have an access
* method defined so that their partitions can inherit it, but they do not set
* rd_tableam; hence, this is handled specially outside of this macro.
*/
#define RELKIND_HAS_TABLE_AM(relkind) \
((relkind) == RELKIND_RELATION || \
(relkind) == RELKIND_TOASTVALUE || \
(relkind) == RELKIND_MATVIEW)
// clang-format on
#endif
TupleDesc
RelationGetDescr(Relation rel) {
return rel->rd_att;
}
int
GetTupleDescNatts(const TupleDesc tupleDesc) {
return tupleDesc->natts;
}
const char *
GetAttName(const Form_pg_attribute att) {
return NameStr(att->attname);
}
Form_pg_attribute
GetAttr(const TupleDesc tupleDesc, int i) {
return &tupleDesc->attrs[i];
}
bool
TupleIsNull(TupleTableSlot *slot) {
return TupIsNull(slot);
}
void
SlotGetAllAttrs(TupleTableSlot *slot) {
PostgresFunctionGuard(slot_getallattrs, slot);
}
Relation
OpenRelation(Oid relationId) {
if (PostgresFunctionGuard(check_enable_rls, relationId, InvalidOid, false) == RLS_ENABLED) {
throw duckdb::NotImplementedException(
"Cannot use \"%s\" relation in a DuckDB query, because RLS is enabled on it",
PostgresFunctionGuard(get_rel_name, relationId));
}
/*
* We always open & close the relation using the
* TopTransactionResourceOwner to avoid having to close the relation
* whenever Postgres switches resource owners, because opening a relation
* with one resource owner and closing it with another is not allowed.
*/
ResourceOwner saveResourceOwner = CurrentResourceOwner;
CurrentResourceOwner = TopTransactionResourceOwner;
auto rel = PostgresFunctionGuard(relation_open, relationId, AccessShareLock);
CurrentResourceOwner = saveResourceOwner;
return rel;
}
void
CloseRelation(Relation rel) {
/*
* We always open & close the relation using the
* TopTransactionResourceOwner to avoid having to close the relation
* whenever Postgres switches resource owners, because opening a relation
* with one resource owner and closing it with another is not allowed.
*/
ResourceOwner saveResourceOwner = CurrentResourceOwner;
CurrentResourceOwner = TopTransactionResourceOwner;
PostgresFunctionGuard(relation_close, rel, NoLock);
CurrentResourceOwner = saveResourceOwner;
}
double
EstimateRelSize(Relation rel) {
Cardinality cardinality = 0;
if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind) || rel->rd_rel->relkind == RELKIND_INDEX) {
BlockNumber pages;
double allvisfrac;
PostgresFunctionGuard(estimate_rel_size, rel, nullptr, &pages, &cardinality, &allvisfrac);
}
return cardinality;
}
Oid
PGGetRelidFromSchemaAndTable(const char *schema_name, const char *entry_name) {
List *name_list = NIL;
name_list = lappend(name_list, makeString(pstrdup(schema_name)));
name_list = lappend(name_list, makeString(pstrdup(entry_name)));
RangeVar *table_range_var = makeRangeVarFromNameList(name_list);
return RangeVarGetRelid(table_range_var, AccessShareLock, true);
}
Oid
GetRelidFromSchemaAndTable(const char *schema_name, const char *entry_name) {
return PostgresFunctionGuard(PGGetRelidFromSchemaAndTable, schema_name, entry_name);
}
bool
IsValidOid(Oid oid) {
return oid != InvalidOid;
}
bool
IsValidBlockNumber(BlockNumber block_number) {
return block_number != InvalidBlockNumber;
}
/*
* generate_qualified_relation_name
* Compute the name to display for a relation specified by OID
*
* As above, but unconditionally schema-qualify the name.
*/
static char *
GenerateQualifiedRelationName_Unsafe(Relation rel) {
char *nspname = get_namespace_name_or_temp(rel->rd_rel->relnamespace);
if (!nspname)
elog(ERROR, "cache lookup failed for namespace %u", rel->rd_rel->relnamespace);
return quote_qualified_identifier(nspname, NameStr(rel->rd_rel->relname));
}
char *
GenerateQualifiedRelationName(Relation rel) {
return PostgresFunctionGuard(GenerateQualifiedRelationName_Unsafe, rel);
}
const char *
QuoteIdentifier(const char *ident) {
return PostgresFunctionGuard(quote_identifier, ident);
}
const char *
GetRelationName(Relation rel) {
return RelationGetRelationName(rel);
}
} // namespace pgduckdb