postgres_extension/executor/spi.rs
1
2use std::ffi::{CString,CStr};
3use crate::utils::memutils::MemoryContext;
4use libc::*;
5
6/* Plans are opaque structs for standard users of SPI */
7pub type SPIPlanPtr = *mut _SPI_plan;
8pub type HeapTuple = *mut HeapTupleData;
9pub type TupleDesc = *mut TupleDescData;
10pub type SubTransactionId = u32;
11
12#[repr(C)]
13pub struct TupleDescData { pub natts: c_int, _private: [u8; 0] }
14#[repr(C)]
15pub struct HeapTupleData { _private: [u8; 0] }
16#[repr(C)]
17pub struct _SPI_plan { _private: [u8; 0] }
18#[repr(C)]
19pub struct slist_node { _private: [u8; 0] }
20
21#[repr(C)]
22pub struct SPITupleTable
23{
24 tuptabcxt: MemoryContext, /* memory context of result table */
25 alloced: u64, /* # of alloced vals */
26 free: u64, /* # of free vals */
27 pub tupdesc: TupleDesc, /* tuple descriptor */
28 pub vals: *mut HeapTuple, /* tuples */
29 next: *mut slist_node, /* link for internal bookkeeping */
30 subid: SubTransactionId, /* subxact in which tuptable was created */
31}
32
33pub const SPI_ERROR_CONNECT: i32 = -1;
34pub const SPI_ERROR_COPY: i32 = -2;
35pub const SPI_ERROR_OPUNKNOWN: i32 = -3;
36pub const SPI_ERROR_UNCONNECTED: i32 = -4;
37pub const SPI_ERROR_CURSOR: i32 = -5; /* not used anymore */
38pub const SPI_ERROR_ARGUMENT: i32 = -6;
39pub const SPI_ERROR_PARAM: i32 = -7;
40pub const SPI_ERROR_TRANSACTION: i32 = -8;
41pub const SPI_ERROR_NOATTRIBUTE: i32 = -9;
42pub const SPI_ERROR_NOOUTFUNC: i32 = -10;
43pub const SPI_ERROR_TYPUNKNOWN: i32 = -11;
44pub const SPI_ERROR_REL_DUPLICATE: i32 = -12;
45pub const SPI_ERROR_REL_NOT_FOUND: i32 = -13;
46
47pub const SPI_OK_CONNECT: i32 = 1;
48pub const SPI_OK_FINISH: i32 = 2;
49pub const SPI_OK_FETCH: i32 = 3;
50pub const SPI_OK_UTILITY: i32 = 4;
51pub const SPI_OK_SELECT: i32 = 5;
52pub const SPI_OK_SELINTO: i32 = 6;
53pub const SPI_OK_INSERT: i32 = 7;
54pub const SPI_OK_DELETE: i32 = 8;
55pub const SPI_OK_UPDATE: i32 = 9;
56pub const SPI_OK_CURSOR: i32 = 10;
57pub const SPI_OK_INSERT_RETURNING: i32 = 11;
58pub const SPI_OK_DELETE_RETURNING: i32 = 12;
59pub const SPI_OK_UPDATE_RETURNING: i32 = 13;
60pub const SPI_OK_REWRITTEN: i32 = 14;
61pub const SPI_OK_REL_REGISTER: i32 = 15;
62pub const SPI_OK_REL_UNREGISTER: i32 = 16;
63pub const SPI_OK_TD_REGISTER: i32 = 17;
64pub const SPI_OPT_NONATOMIC: i32 = (1 << 0);
65
66pub mod c {
67 use libc::*;
68 use super::*;
69 extern {
70 pub static SPI_processed: u64;
71 pub static SPI_tuptable: *mut SPITupleTable;
72 pub static SPI_result: c_int;
73
74 pub fn SPI_connect() -> c_int;
75 pub fn SPI_connect_ext(options: c_int) -> c_int;
76 pub fn SPI_finish() -> c_int;
77 pub fn SPI_execute(src: *const c_char, read_only: bool,
78 tcount: c_long) -> c_int;
79 /*
80 pub fn SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
81 bool read_only, long tcount) -> c_int;
82 pub fn SPI_execute_plan_with_paramlist(SPIPlanPtr plan,
83 ParamListInfo params,
84 bool read_only, long tcount) -> c_int;
85 */
86 pub fn SPI_exec(src: *const c_char, tcount: c_long) -> c_int;
87 /*
88 pub fn SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls,
89 long tcount) -> c_int;
90 pub fn SPI_execute_snapshot(SPIPlanPtr plan,
91 Datum *Values, const char *Nulls,
92 Snapshot snapshot,
93 Snapshot crosscheck_snapshot,
94 bool read_only, bool fire_triggers,
95 tcount: c_long) -> c_int;
96 pub fn SPI_execute_with_args(const char *src,
97 int nargs, Oid *argtypes,
98 Datum *Values, const char *Nulls,
99 bool read_only, long tcount) -> int;
100 pub fn SPI_prepare(const char *src, int nargs, Oid *argtypes) -> SPIPlanPtr;
101 pub fn SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
102 int cursorOptions) -> SPIPlanPtr;
103 pub fn SPI_prepare_params(const char *src,
104 ParserSetupHook parserSetup,
105 void *parserSetupArg,
106 int cursorOptions) -> SPIPlanPtr;
107 pub fn SPI_keepplan(SPIPlanPtr plan) -> int;
108 pub fn SPI_saveplan(SPIPlanPtr plan) -> SPIPlanPtr;
109 pub fn SPI_freeplan(SPIPlanPtr plan) -> int;
110
111 pub fn SPI_getargtypeid(SPIPlanPtr plan, int argIndex) -> Oid;
112 pub fn SPI_getargcount(SPIPlanPtr plan) -> int;
113 pub fn SPI_is_cursor_plan(SPIPlanPtr plan) -> bool;
114 pub fn SPI_plan_is_valid(SPIPlanPtr plan) -> bool;
115 pub fn SPI_result_code_string(int code) -> *const c_char;
116
117 pub fn SPI_plan_get_plan_sources(SPIPlanPtr plan) -> *mut List;
118 pub fn SPI_plan_get_cached_plan(SPIPlanPtr plan) -> *mut CachedPlan;
119
120 pub fn SPI_copytuple(HeapTuple tuple) -> HeapTuple;
121 pub fn SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc) -> HeapTupleHeader;
122 pub fn SPI_modifytuple(Relation rel, HeapTuple tuple, int natts,
123 int *attnum, Datum *Values, const char *Nulls) -> HeapTuple;
124 pub fn SPI_fnumber(TupleDesc tupdesc, const char *fname) -> int;
125 pub fn SPI_fname(TupleDesc tupdesc, int fnumber) -> *const c_char;
126 */
127 pub fn SPI_getvalue(tuple: HeapTuple, tupdesc: TupleDesc,
128 fnumber: c_int) -> *const c_char;
129 /*
130 pub fn SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull) -> Datum;
131 pub fn SPI_gettype(TupleDesc tupdesc, int fnumber) -> *const c_char
132 pub fn SPI_gettypeid(TupleDesc tupdesc, int fnumber) -> Oid;
133 pub fn SPI_getrelname(Relation rel) -> *const c_char;
134 pub fn SPI_getnspname(Relation rel) -> *const c_char;
135 pub fn SPI_palloc(Size size) -> *mut c_void;
136 pub fn SPI_repalloc(void *pointer, Size size) -> *mut c_void;
137 pub fn SPI_pfree(void *pointer);
138 pub fn SPI_datumTransfer(Datum value, bool typByVal, int typLen) -> Datum;
139 pub fn SPI_freetuple(HeapTuple pointer) -> void;
140 */
141 pub fn SPI_freetuptable(tuptable: *mut SPITupleTable);
142 /*
143 pub fn SPI_cursor_open(const char *name, SPIPlanPtr plan,
144 Datum *Values, const char *Nulls, bool read_only) -> Portal;
145 pub fn SPI_cursor_open_with_args(const char *name,
146 const char *src,
147 int nargs, Oid *argtypes,
148 Datum *Values, const char *Nulls,
149 bool read_only, int cursorOptions) -> Portal;
150 pub fn SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan,
151 ParamListInfo params, bool read_only) -> Portal;
152 pub fn SPI_cursor_find(const char *name) -> Portal;
153 pub fn SPI_cursor_fetch(Portal portal, bool forward, long count) -> void;
154 pub fn SPI_cursor_move(Portal portal, bool forward, long count) -> void;
155 pub fn SPI_scroll_cursor_fetch(Portal, FetchDirection direction, long count) -> void;
156 pub fn SPI_scroll_cursor_move(Portal, FetchDirection direction, long count) -> void;
157 pub fn SPI_cursor_close(Portal portal) -> void;
158
159 pub fn SPI_register_relation(EphemeralNamedRelation enr) -> int;
160 pub fn SPI_unregister_relation(const char *name) -> int;
161 pub fn SPI_register_trigger_data(tdata: *mut TriggerData) -> c_int;
162
163 pub fn SPI_start_transaction();
164 pub fn SPI_commit();
165 pub fn SPI_rollback();
166
167 pub fn SPICleanup();
168 pub fn AtEOXact_SPI(isCommit: bool);
169 pub fn AtEOSubXact_SPI(isCommit: bool, mySubid: SubTransactionId);
170 pub fn SPI_inside_nonatomic_context() -> bool;
171 */
172 }
173}
174
175
176/*
177
178 let spi = spi_connect(options);
179 let res1 = spi.exec("select * from foo");
180 let res2 = spi.exec("select * from bar");
181 spi.freeresult(res2);
182 let res3 = spi.exec("select * from baz");
183 drop(spi);
184 */
185
186pub struct SPIConnection;
187
188pub struct SPIResult<'a> {
189 pub status: i32,
190 processed: u64,
191 tuptable: &'a mut SPITupleTable,
192}
193
194impl SPIConnection {
195 pub fn execute(&self, query: &str, readonly: bool) -> Result<SPIResult,i32> {
196 let query_cstring = CString::new(query).unwrap();
197 let query_ptr = query_cstring.as_ptr();
198 unsafe {
199 let status = c::SPI_execute(query_ptr, readonly, 0);
200 if status >= 0 {
201 return Ok(SPIResult {
202 status: status,
203 processed: c::SPI_processed,
204 tuptable: &mut *c::SPI_tuptable,
205 })
206 } else {
207 return Err(status);
208 }
209 }
210 }
211}
212
213impl Drop for SPIConnection {
214 fn drop(&mut self) {
215 unsafe {
216 c::SPI_finish();
217 }
218 }
219}
220
221impl<'a> SPIResult<'a> {
222 pub fn tuples(&self) -> &'a [&HeapTupleData] {
223 unsafe {
224 let vals: *const &HeapTupleData = (*self.tuptable).vals
225 as *const &HeapTupleData;
226 return std::slice::from_raw_parts(vals, self.processed as usize);
227 }
228 }
229 pub fn tupdesc(&self) -> &'a TupleDescData {
230 unsafe {
231 return &*(*self.tuptable).tupdesc;
232 }
233 }
234}
235
236impl<'a> Drop for SPIResult<'a> {
237 fn drop(&mut self) {
238 unsafe {
239 c::SPI_freetuptable(self.tuptable);
240 }
241 }
242}
243
244pub fn spi_connect() -> SPIConnection {
245 unsafe {
246 c::SPI_connect();
247 }
248 return SPIConnection {};
249}
250
251pub fn spi_getvalue(tuple: &HeapTupleData,
252 tupdesc: &TupleDescData,
253 attno: c_int) -> String {
254 unsafe {
255 let tuple_ptr: HeapTuple = tuple as *const HeapTupleData
256 as *mut HeapTupleData;
257 let tupdesc_ptr: TupleDesc = tupdesc as *const TupleDescData
258 as *mut TupleDescData;
259 let val_ptr = c::SPI_getvalue(tuple_ptr, tupdesc_ptr, attno);
260 let val_str = CStr::from_ptr(val_ptr).to_str().unwrap();
261 return CString::new(val_str).unwrap().into_string().unwrap();
262 };
263}