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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
use std::ffi::{CString,CStr};
use crate::utils::memutils::MemoryContext;
use libc::*;
pub type SPIPlanPtr = *mut _SPI_plan;
pub type HeapTuple = *mut HeapTupleData;
pub type TupleDesc = *mut TupleDescData;
pub type SubTransactionId = u32;
#[repr(C)]
pub struct TupleDescData { pub natts: c_int, _private: [u8; 0] }
#[repr(C)]
pub struct HeapTupleData { _private: [u8; 0] }
#[repr(C)]
pub struct _SPI_plan { _private: [u8; 0] }
#[repr(C)]
pub struct slist_node { _private: [u8; 0] }
#[repr(C)]
pub struct SPITupleTable
{
tuptabcxt: MemoryContext,
alloced: u64,
free: u64,
pub tupdesc: TupleDesc,
pub vals: *mut HeapTuple,
next: *mut slist_node,
subid: SubTransactionId,
}
pub const SPI_ERROR_CONNECT: i32 = -1;
pub const SPI_ERROR_COPY: i32 = -2;
pub const SPI_ERROR_OPUNKNOWN: i32 = -3;
pub const SPI_ERROR_UNCONNECTED: i32 = -4;
pub const SPI_ERROR_CURSOR: i32 = -5;
pub const SPI_ERROR_ARGUMENT: i32 = -6;
pub const SPI_ERROR_PARAM: i32 = -7;
pub const SPI_ERROR_TRANSACTION: i32 = -8;
pub const SPI_ERROR_NOATTRIBUTE: i32 = -9;
pub const SPI_ERROR_NOOUTFUNC: i32 = -10;
pub const SPI_ERROR_TYPUNKNOWN: i32 = -11;
pub const SPI_ERROR_REL_DUPLICATE: i32 = -12;
pub const SPI_ERROR_REL_NOT_FOUND: i32 = -13;
pub const SPI_OK_CONNECT: i32 = 1;
pub const SPI_OK_FINISH: i32 = 2;
pub const SPI_OK_FETCH: i32 = 3;
pub const SPI_OK_UTILITY: i32 = 4;
pub const SPI_OK_SELECT: i32 = 5;
pub const SPI_OK_SELINTO: i32 = 6;
pub const SPI_OK_INSERT: i32 = 7;
pub const SPI_OK_DELETE: i32 = 8;
pub const SPI_OK_UPDATE: i32 = 9;
pub const SPI_OK_CURSOR: i32 = 10;
pub const SPI_OK_INSERT_RETURNING: i32 = 11;
pub const SPI_OK_DELETE_RETURNING: i32 = 12;
pub const SPI_OK_UPDATE_RETURNING: i32 = 13;
pub const SPI_OK_REWRITTEN: i32 = 14;
pub const SPI_OK_REL_REGISTER: i32 = 15;
pub const SPI_OK_REL_UNREGISTER: i32 = 16;
pub const SPI_OK_TD_REGISTER: i32 = 17;
pub const SPI_OPT_NONATOMIC: i32 = (1 << 0);
pub mod c {
use libc::*;
use super::*;
extern {
pub static SPI_processed: u64;
pub static SPI_tuptable: *mut SPITupleTable;
pub static SPI_result: c_int;
pub fn SPI_connect() -> c_int;
pub fn SPI_connect_ext(options: c_int) -> c_int;
pub fn SPI_finish() -> c_int;
pub fn SPI_execute(src: *const c_char, read_only: bool,
tcount: c_long) -> c_int;
pub fn SPI_exec(src: *const c_char, tcount: c_long) -> c_int;
pub fn SPI_getvalue(tuple: HeapTuple, tupdesc: TupleDesc,
fnumber: c_int) -> *const c_char;
pub fn SPI_freetuptable(tuptable: *mut SPITupleTable);
}
}
pub struct SPIConnection;
pub struct SPIResult<'a> {
pub status: i32,
processed: u64,
tuptable: &'a mut SPITupleTable,
}
impl SPIConnection {
pub fn execute(&self, query: &str, readonly: bool) -> Result<SPIResult,i32> {
let query_cstring = CString::new(query).unwrap();
let query_ptr = query_cstring.as_ptr();
unsafe {
let status = c::SPI_execute(query_ptr, readonly, 0);
if status >= 0 {
return Ok(SPIResult {
status: status,
processed: c::SPI_processed,
tuptable: &mut *c::SPI_tuptable,
})
} else {
return Err(status);
}
}
}
}
impl Drop for SPIConnection {
fn drop(&mut self) {
unsafe {
c::SPI_finish();
}
}
}
impl<'a> SPIResult<'a> {
pub fn tuples(&self) -> &'a [&HeapTupleData] {
unsafe {
let vals: *const &HeapTupleData = (*self.tuptable).vals
as *const &HeapTupleData;
return std::slice::from_raw_parts(vals, self.processed as usize);
}
}
pub fn tupdesc(&self) -> &'a TupleDescData {
unsafe {
return &*(*self.tuptable).tupdesc;
}
}
}
impl<'a> Drop for SPIResult<'a> {
fn drop(&mut self) {
unsafe {
c::SPI_freetuptable(self.tuptable);
}
}
}
pub fn spi_connect() -> SPIConnection {
unsafe {
c::SPI_connect();
}
return SPIConnection {};
}
pub fn spi_getvalue(tuple: &HeapTupleData,
tupdesc: &TupleDescData,
attno: c_int) -> String {
unsafe {
let tuple_ptr: HeapTuple = tuple as *const HeapTupleData
as *mut HeapTupleData;
let tupdesc_ptr: TupleDesc = tupdesc as *const TupleDescData
as *mut TupleDescData;
let val_ptr = c::SPI_getvalue(tuple_ptr, tupdesc_ptr, attno);
let val_str = CStr::from_ptr(val_ptr).to_str().unwrap();
return CString::new(val_str).unwrap().into_string().unwrap();
};
}