rts-postgresql.c
1 //! @file rts-postgresql.c
2 //! @author J. Marcel van der Veer
3
4 //! @section Copyright
5 //!
6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
7 //! Copyright 2001-2025 J. Marcel van der Veer [algol68g@xs4all.nl].
8
9 //! @section License
10 //!
11 //! This program is free software; you can redistribute it and/or modify it
12 //! under the terms of the GNU General Public License as published by the
13 //! Free Software Foundation; either version 3 of the License, or
14 //! (at your option) any later version.
15 //!
16 //! This program is distributed in the hope that it will be useful, but
17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 //! more details. You should have received a copy of the GNU General Public
20 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
21
22 //! @section Synopsis
23 //!
24 //! PostgreSQL libpq interface.
25
26 // PostgreSQL libpq interface based on initial work by Jaap Boender.
27 // Wraps "connection" and "result" objects in a FILE variable to support
28 // multiple connections.
29 //
30 // Error codes:
31 // 0 Success
32 // -1 No connection
33 // -2 No result
34 // -3 Other error
35
36 #include "a68g.h"
37 #include "a68g-prelude.h"
38 #include "a68g-genie.h"
39 #include "a68g-transput.h"
40
41 #if defined (HAVE_POSTGRESQL)
42
43 #define LIBPQ_STRING "PostgreSQL libq"
44 #define ERROR_NOT_CONNECTED "not connected to a database"
45 #define ERROR_NO_QUERY_RESULT "no query result available"
46
47 #define NO_PGCONN ((PGconn *) NULL)
48 #define NO_PGRESULT ((PGresult *) NULL)
49
50 //! @brief PROC pg connect db (REF FILE, STRING, REF STRING) INT
51
52 void genie_pq_connectdb (NODE_T * p)
53 {
54 A68G_REF ref_string, ref_file, conninfo;
55 POP_REF (p, &ref_string);
56 CHECK_REF (p, ref_string, M_REF_STRING);
57 POP_REF (p, &conninfo);
58 POP_REF (p, &ref_file);
59 CHECK_REF (p, ref_file, M_REF_FILE);
60 if (IS_IN_HEAP (&ref_file) && !IS_IN_HEAP (&ref_string)) {
61 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_SCOPE_DYNAMIC_1, M_REF_STRING);
62 exit_genie (p, A68G_RUNTIME_ERROR);
63 } else if (IS_IN_FRAME (&ref_file) && IS_IN_FRAME (&ref_string)) {
64 if (REF_SCOPE (&ref_string) > REF_SCOPE (&ref_file)) {
65 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_SCOPE_DYNAMIC_1, M_REF_STRING);
66 exit_genie (p, A68G_RUNTIME_ERROR);
67 }
68 }
69 // Initialise the file.
70 A68G_FILE *file = FILE_DEREF (&ref_file);
71 if (OPENED (file)) {
72 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_FILE_ALREADY_OPEN);
73 exit_genie (p, A68G_RUNTIME_ERROR);
74 }
75 STATUS (file) = INIT_MASK;
76 CHANNEL (file) = A68G (associate_channel);
77 OPENED (file) = A68G_TRUE;
78 APPEND (file) = A68G_FALSE;
79 OPEN_EXCLUSIVE (file) = A68G_FALSE;
80 READ_MOOD (file) = A68G_FALSE;
81 WRITE_MOOD (file) = A68G_FALSE;
82 CHAR_MOOD (file) = A68G_FALSE;
83 DRAW_MOOD (file) = A68G_FALSE;
84 TMP_FILE (file) = A68G_FALSE;
85 if (INITIALISED (&(IDENTIFICATION (file))) && !IS_NIL (IDENTIFICATION (file))) {
86 UNBLOCK_GC_HANDLE (&(IDENTIFICATION (file)));
87 }
88 IDENTIFICATION (file) = nil_ref;
89 TERMINATOR (file) = nil_ref;
90 FORMAT (file) = nil_format;
91 FD (file) = A68G_NO_FILE;
92 if (INITIALISED (&(STRING (file))) && !IS_NIL (STRING (file))) {
93 UNBLOCK_GC_HANDLE (&(STRING (file)));
94 }
95 STRING (file) = ref_string;
96 BLOCK_GC_HANDLE (&(STRING (file)));
97 STRPOS (file) = 0;
98 STREAM (&DEVICE (file)) = NULL;
99 set_default_event_procedures (file);
100 // Establish a connection.
101 A68G_REF ref_z = heap_generator (p, M_C_STRING, 1 + a68g_string_size (p, conninfo));
102 CONNECTION (file) = PQconnectdb (a_to_c_string (p, DEREF (char, &ref_z), conninfo));
103 RESULT (file) = NO_PGRESULT;
104 if (CONNECTION (file) == NO_PGCONN) {
105 PUSH_PRIMAL (p, -3, INT);
106 }
107 (void) PQsetErrorVerbosity (CONNECTION (file), PQERRORS_DEFAULT);
108 if (PQstatus (CONNECTION (file)) != CONNECTION_OK) {
109 PUSH_PRIMAL (p, -1, INT);
110 } else {
111 PUSH_PRIMAL (p, 0, INT);
112 }
113 }
114
115 //! @brief PROC pq finish (REF FILE) VOID
116
117 void genie_pq_finish (NODE_T * p)
118 {
119 A68G_REF ref_file;
120 POP_REF (p, &ref_file);
121 CHECK_REF (p, ref_file, M_REF_FILE);
122 A68G_FILE *file = FILE_DEREF (&ref_file);
123 CHECK_INIT (p, INITIALISED (file), M_FILE);
124 if (CONNECTION (file) == NO_PGCONN) {
125 PUSH_PRIMAL (p, -1, INT);
126 return;
127 }
128 if (RESULT (file) != NO_PGRESULT) {
129 PQclear (RESULT (file));
130 }
131 PQfinish (CONNECTION (file));
132 CONNECTION (file) = NO_PGCONN;
133 RESULT (file) = NO_PGRESULT;
134 PUSH_PRIMAL (p, 0, INT);
135 }
136
137 //! @brief PROC pq reset (REF FILE) VOID
138
139 void genie_pq_reset (NODE_T * p)
140 {
141 A68G_REF ref_file;
142 POP_REF (p, &ref_file);
143 CHECK_REF (p, ref_file, M_REF_FILE);
144 A68G_FILE *file = FILE_DEREF (&ref_file);
145 CHECK_INIT (p, INITIALISED (file), M_FILE);
146 if (CONNECTION (file) == NO_PGCONN) {
147 PUSH_PRIMAL (p, -1, INT);
148 return;
149 }
150 if (RESULT (file) != NO_PGRESULT) {
151 PQclear (RESULT (file));
152 }
153 PQreset (CONNECTION (file));
154 PUSH_PRIMAL (p, 0, INT);
155 }
156
157 //! @brief PROC pq exec = (REF FILE, STRING) INT
158
159 void genie_pq_exec (NODE_T * p)
160 {
161 A68G_REF query, ref_file;
162 POP_REF (p, &query);
163 POP_REF (p, &ref_file);
164 CHECK_REF (p, ref_file, M_REF_FILE);
165 A68G_FILE *file = FILE_DEREF (&ref_file);
166 CHECK_INIT (p, INITIALISED (file), M_FILE);
167 if (CONNECTION (file) == NO_PGCONN) {
168 PUSH_PRIMAL (p, -1, INT);
169 return;
170 }
171 if (RESULT (file) != NO_PGRESULT) {
172 PQclear (RESULT (file));
173 }
174 A68G_REF ref_z = heap_generator (p, M_C_STRING, 1 + a68g_string_size (p, query));
175 RESULT (file) = PQexec (CONNECTION (file), a_to_c_string (p, DEREF (char, &ref_z), query));
176 if ((PQresultStatus (RESULT (file)) != PGRES_TUPLES_OK)
177 && (PQresultStatus (RESULT (file)) != PGRES_COMMAND_OK)) {
178 PUSH_PRIMAL (p, -3, INT);
179 } else {
180 PUSH_PRIMAL (p, 0, INT);
181 }
182 }
183
184 //! @brief PROC pq parameterstatus (REF FILE) INT
185
186 void genie_pq_parameterstatus (NODE_T * p)
187 {
188 A68G_REF parameter, ref_file;
189 POP_REF (p, ¶meter);
190 POP_REF (p, &ref_file);
191 CHECK_REF (p, ref_file, M_REF_FILE);
192 A68G_FILE *file = FILE_DEREF (&ref_file);
193 CHECK_INIT (p, INITIALISED (file), M_FILE);
194 if (CONNECTION (file) == NO_PGCONN) {
195 PUSH_PRIMAL (p, -1, INT);
196 return;
197 }
198 A68G_REF ref_z = heap_generator (p, M_C_STRING, 1 + a68g_string_size (p, parameter));
199 if (!IS_NIL (STRING (file))) {
200 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, (char *) PQparameterStatus (CONNECTION (file), a_to_c_string (p, DEREF (char, &ref_z), parameter)), DEFAULT_WIDTH);
201 PUSH_PRIMAL (p, 0, INT);
202 } else {
203 PUSH_PRIMAL (p, -3, INT);
204 }
205 }
206
207 //! @brief PROC pq cmdstatus (REF FILE) INT
208
209 void genie_pq_cmdstatus (NODE_T * p)
210 {
211 A68G_REF ref_file;
212 POP_REF (p, &ref_file);
213 CHECK_REF (p, ref_file, M_REF_FILE);
214 A68G_FILE *file = FILE_DEREF (&ref_file);
215 CHECK_INIT (p, INITIALISED (file), M_FILE);
216 if (CONNECTION (file) == NO_PGCONN) {
217 PUSH_PRIMAL (p, -1, INT);
218 return;
219 }
220 if (RESULT (file) == NO_PGRESULT) {
221 PUSH_PRIMAL (p, -1, INT);
222 return;
223 }
224 if (!IS_NIL (STRING (file))) {
225 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, PQcmdStatus (RESULT (file)), DEFAULT_WIDTH);
226 STRPOS (file) = 0;
227 PUSH_PRIMAL (p, 0, INT);
228 } else {
229 PUSH_PRIMAL (p, -3, INT);
230 }
231 }
232
233 //! @brief PROC pq cmdtuples (REF FILE) INT
234
235 void genie_pq_cmdtuples (NODE_T * p)
236 {
237 A68G_REF ref_file;
238 POP_REF (p, &ref_file);
239 CHECK_REF (p, ref_file, M_REF_FILE);
240 A68G_FILE *file = FILE_DEREF (&ref_file);
241 CHECK_INIT (p, INITIALISED (file), M_FILE);
242 if (CONNECTION (file) == NO_PGCONN) {
243 PUSH_PRIMAL (p, -1, INT);
244 return;
245 }
246 if (RESULT (file) == NO_PGRESULT) {
247 PUSH_PRIMAL (p, -1, INT);
248 return;
249 }
250 if (!IS_NIL (STRING (file))) {
251 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, PQcmdTuples (RESULT (file)), DEFAULT_WIDTH);
252 STRPOS (file) = 0;
253 PUSH_PRIMAL (p, 0, INT);
254 } else {
255 PUSH_PRIMAL (p, -3, INT);
256 }
257 }
258
259 //! @brief PROC pq ntuples (REF FILE) INT
260
261 void genie_pq_ntuples (NODE_T * p)
262 {
263 A68G_REF ref_file;
264 POP_REF (p, &ref_file);
265 CHECK_REF (p, ref_file, M_REF_FILE);
266 A68G_FILE *file = FILE_DEREF (&ref_file);
267 CHECK_INIT (p, INITIALISED (file), M_FILE);
268 if (CONNECTION (file) == NO_PGCONN) {
269 PUSH_PRIMAL (p, -1, INT);
270 return;
271 }
272 if (RESULT (file) == NO_PGRESULT) {
273 PUSH_PRIMAL (p, -2, INT);
274 return;
275 }
276 PUSH_PRIMAL (p, (PQresultStatus (RESULT (file))) == PGRES_TUPLES_OK ? PQntuples (RESULT (file)) : -3, INT);
277 }
278
279 //! @brief PROC pq nfields (REF FILE) INT
280
281 void genie_pq_nfields (NODE_T * p)
282 {
283 A68G_REF ref_file;
284 POP_REF (p, &ref_file);
285 CHECK_REF (p, ref_file, M_REF_FILE);
286 A68G_FILE *file = FILE_DEREF (&ref_file);
287 CHECK_INIT (p, INITIALISED (file), M_FILE);
288 if (CONNECTION (file) == NO_PGCONN) {
289 PUSH_PRIMAL (p, -1, INT);
290 return;
291 }
292 if (RESULT (file) == NO_PGRESULT) {
293 PUSH_PRIMAL (p, -2, INT);
294 return;
295 }
296 PUSH_PRIMAL (p, (PQresultStatus (RESULT (file))) == PGRES_TUPLES_OK ? PQnfields (RESULT (file)) : -3, INT);
297 }
298
299 //! @brief PROC pq fname (REF FILE, INT) INT
300
301 void genie_pq_fname (NODE_T * p)
302 {
303 A68G_INT a68g_index; A68G_REF ref_file;
304 POP_OBJECT (p, &a68g_index, A68G_INT);
305 CHECK_INIT (p, INITIALISED (&a68g_index), M_INT);
306 POP_REF (p, &ref_file);
307 CHECK_REF (p, ref_file, M_REF_FILE);
308 A68G_FILE *file = FILE_DEREF (&ref_file);
309 CHECK_INIT (p, INITIALISED (file), M_FILE);
310 if (CONNECTION (file) == NO_PGCONN) {
311 PUSH_PRIMAL (p, -1, INT);
312 return;
313 }
314 if (RESULT (file) == NO_PGRESULT) {
315 PUSH_PRIMAL (p, -2, INT);
316 return;
317 }
318 int upb = (PQresultStatus (RESULT (file)) == PGRES_TUPLES_OK ? PQnfields (RESULT (file)) : 0);
319 if (VALUE (&a68g_index) < 1 || VALUE (&a68g_index) > upb) {
320 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INDEX_OUT_OF_BOUNDS);
321 exit_genie (p, A68G_RUNTIME_ERROR);
322 }
323 if (!IS_NIL (STRING (file))) {
324 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, PQfname (RESULT (file), VALUE (&a68g_index) - 1), DEFAULT_WIDTH);
325 STRPOS (file) = 0;
326 }
327 PUSH_PRIMAL (p, 0, INT);
328 }
329
330 //! @brief PROC pq fnumber = (REF FILE, STRING) INT
331
332 void genie_pq_fnumber (NODE_T * p)
333 {
334 A68G_REF name, ref_file;
335 POP_REF (p, &name);
336 POP_REF (p, &ref_file);
337 CHECK_REF (p, ref_file, M_REF_FILE);
338 A68G_FILE *file = FILE_DEREF (&ref_file);
339 CHECK_INIT (p, INITIALISED (file), M_FILE);
340 if (CONNECTION (file) == NO_PGCONN) {
341 PUSH_PRIMAL (p, -1, INT);
342 return;
343 }
344 if (RESULT (file) == NO_PGRESULT) {
345 PUSH_PRIMAL (p, -2, INT);
346 return;
347 }
348 A68G_REF ref_z = heap_generator (p, M_C_STRING, 1 + a68g_string_size (p, name));
349 int k = PQfnumber (RESULT (file), a_to_c_string (p, DEREF (char, &ref_z), name));
350 if (k == -1) {
351 PUSH_PRIMAL (p, -3, INT);
352 } else {
353 PUSH_PRIMAL (p, k + 1, INT);
354 }
355 }
356
357 //! @brief PROC pq fformat (REF FILE, INT) INT
358
359 void genie_pq_fformat (NODE_T * p)
360 {
361 A68G_INT a68g_index; A68G_REF ref_file;
362 POP_OBJECT (p, &a68g_index, A68G_INT);
363 CHECK_INIT (p, INITIALISED (&a68g_index), M_INT);
364 POP_REF (p, &ref_file);
365 CHECK_REF (p, ref_file, M_REF_FILE);
366 A68G_FILE *file = FILE_DEREF (&ref_file);
367 CHECK_INIT (p, INITIALISED (file), M_FILE);
368 if (CONNECTION (file) == NO_PGCONN) {
369 PUSH_PRIMAL (p, -1, INT);
370 return;
371 }
372 if (RESULT (file) == NO_PGRESULT) {
373 PUSH_PRIMAL (p, -2, INT);
374 return;
375 }
376 int upb = (PQresultStatus (RESULT (file)) == PGRES_TUPLES_OK ? PQnfields (RESULT (file)) : 0);
377 if (VALUE (&a68g_index) < 1 || VALUE (&a68g_index) > upb) {
378 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INDEX_OUT_OF_BOUNDS);
379 exit_genie (p, A68G_RUNTIME_ERROR);
380 }
381 PUSH_PRIMAL (p, PQfformat (RESULT (file), VALUE (&a68g_index) - 1), INT);
382 }
383
384 //! @brief PROC pq getvalue (REF FILE, INT, INT) INT
385
386 void genie_pq_getvalue (NODE_T * p)
387 {
388 A68G_INT row, column; A68G_REF ref_file;
389 POP_OBJECT (p, &column, A68G_INT);
390 CHECK_INIT (p, INITIALISED (&column), M_INT);
391 POP_OBJECT (p, &row, A68G_INT);
392 CHECK_INIT (p, INITIALISED (&row), M_INT);
393 POP_REF (p, &ref_file);
394 CHECK_REF (p, ref_file, M_REF_FILE);
395 A68G_FILE *file = FILE_DEREF (&ref_file);
396 CHECK_INIT (p, INITIALISED (file), M_FILE);
397 if (CONNECTION (file) == NO_PGCONN) {
398 PUSH_PRIMAL (p, -1, INT);
399 return;
400 }
401 if (RESULT (file) == NO_PGRESULT) {
402 PUSH_PRIMAL (p, -2, INT);
403 return;
404 }
405 int upb = (PQresultStatus (RESULT (file)) == PGRES_TUPLES_OK ? PQnfields (RESULT (file)) : 0);
406 if (VALUE (&column) < 1 || VALUE (&column) > upb) {
407 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INDEX_OUT_OF_BOUNDS);
408 exit_genie (p, A68G_RUNTIME_ERROR);
409 }
410 upb = (PQresultStatus (RESULT (file)) == PGRES_TUPLES_OK ? PQntuples (RESULT (file)) : 0);
411 if (VALUE (&row) < 1 || VALUE (&row) > upb) {
412 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INDEX_OUT_OF_BOUNDS);
413 exit_genie (p, A68G_RUNTIME_ERROR);
414 }
415 char *str = PQgetvalue (RESULT (file), VALUE (&row) - 1, VALUE (&column) - 1);
416 if (str == NULL) {
417 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_NO_QUERY_RESULT);
418 exit_genie (p, A68G_RUNTIME_ERROR);
419 }
420 if (!IS_NIL (STRING (file))) {
421 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, str, DEFAULT_WIDTH);
422 STRPOS (file) = 0;
423 PUSH_PRIMAL (p, 0, INT);
424 } else {
425 PUSH_PRIMAL (p, -3, INT);
426 }
427 }
428
429 //! @brief PROC pq getisnull (REF FILE, INT, INT) INT
430
431 void genie_pq_getisnull (NODE_T * p)
432 {
433 A68G_INT row, column; A68G_REF ref_file;
434 POP_OBJECT (p, &column, A68G_INT);
435 CHECK_INIT (p, INITIALISED (&column), M_INT);
436 POP_OBJECT (p, &row, A68G_INT);
437 CHECK_INIT (p, INITIALISED (&row), M_INT);
438 POP_REF (p, &ref_file);
439 CHECK_REF (p, ref_file, M_REF_FILE);
440 A68G_FILE *file = FILE_DEREF (&ref_file);
441 CHECK_INIT (p, INITIALISED (file), M_FILE);
442 if (CONNECTION (file) == NO_PGCONN) {
443 PUSH_PRIMAL (p, -1, INT);
444 return;
445 }
446 if (RESULT (file) == NO_PGRESULT) {
447 PUSH_PRIMAL (p, -2, INT);
448 return;
449 }
450 int upb = (PQresultStatus (RESULT (file)) == PGRES_TUPLES_OK ? PQnfields (RESULT (file)) : 0);
451 if (VALUE (&column) < 1 || VALUE (&column) > upb) {
452 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INDEX_OUT_OF_BOUNDS);
453 exit_genie (p, A68G_RUNTIME_ERROR);
454 }
455 upb = (PQresultStatus (RESULT (file)) == PGRES_TUPLES_OK ? PQntuples (RESULT (file)) : 0);
456 if (VALUE (&row) < 1 || VALUE (&row) > upb) {
457 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INDEX_OUT_OF_BOUNDS);
458 exit_genie (p, A68G_RUNTIME_ERROR);
459 }
460 PUSH_PRIMAL (p, PQgetisnull (RESULT (file), VALUE (&row) - 1, VALUE (&column) - 1), INT);
461 }
462
463 //! @brief Edit error message string from libpq.
464
465 char *pq_edit (char *str)
466 {
467 if (str == NULL) {
468 return "";
469 } else {
470 static BUFFER edt;
471 char *q = edt;
472 int newlines = 0;
473 size_t len = strlen (str);
474 BOOL_T suppress_blank = A68G_FALSE;
475 while (len > 0 && str[len - 1] == NEWLINE_CHAR) {
476 str[len - 1] = NULL_CHAR;
477 len = strlen (str);
478 }
479 while (str[0] != NULL_CHAR) {
480 if (str[0] == CR_CHAR) {
481 str++;
482 } else if (str[0] == NEWLINE_CHAR) {
483 if (newlines++ == 0) {
484 *(q++) = POINT_CHAR;
485 *(q++) = BLANK_CHAR;
486 *(q++) = '(';
487 } else {
488 *(q++) = BLANK_CHAR;
489 }
490 suppress_blank = A68G_TRUE;
491 str++;
492 } else if (IS_SPACE (str[0])) {
493 if (suppress_blank) {
494 str++;
495 } else {
496 if (str[1] != NEWLINE_CHAR) {
497 *(q++) = BLANK_CHAR;
498 }
499 str++;
500 suppress_blank = A68G_TRUE;
501 }
502 } else {
503 *(q++) = *(str++);
504 suppress_blank = A68G_FALSE;
505 }
506 }
507 if (newlines > 0) {
508 *(q++) = ')';
509 }
510 q[0] = NULL_CHAR;
511 return edt;
512 }
513 }
514
515 //! @brief PROC pq errormessage (REF FILE) INT
516
517 void genie_pq_errormessage (NODE_T * p)
518 {
519 A68G_REF ref_file;
520 POP_REF (p, &ref_file);
521 CHECK_REF (p, ref_file, M_REF_FILE);
522 A68G_FILE *file = FILE_DEREF (&ref_file);
523 CHECK_INIT (p, INITIALISED (file), M_FILE);
524 if (CONNECTION (file) == NO_PGCONN) {
525 PUSH_PRIMAL (p, -1, INT);
526 return;
527 }
528 if (!IS_NIL (STRING (file))) {
529 BUFFER str;
530 if (PQerrorMessage (CONNECTION (file)) != NULL) {
531 a68g_bufcpy (str, pq_edit (PQerrorMessage (CONNECTION (file))), BUFFER_SIZE);
532 size_t upb = strlen (str);
533 if (upb > 0 && str[upb - 1] == NEWLINE_CHAR) {
534 str[upb - 1] = NULL_CHAR;
535 }
536 } else {
537 a68g_bufcpy (str, "no error message available", BUFFER_SIZE);
538 }
539 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, str, DEFAULT_WIDTH);
540 STRPOS (file) = 0;
541 PUSH_PRIMAL (p, 0, INT);
542 } else {
543 PUSH_PRIMAL (p, -3, INT);
544 }
545 }
546
547 //! @brief PROC pq resulterrormessage (REF FILE) INT
548
549 void genie_pq_resulterrormessage (NODE_T * p)
550 {
551 A68G_REF ref_file;
552 POP_REF (p, &ref_file);
553 CHECK_REF (p, ref_file, M_REF_FILE);
554 A68G_FILE *file = FILE_DEREF (&ref_file);
555 CHECK_INIT (p, INITIALISED (file), M_FILE);
556 if (CONNECTION (file) == NO_PGCONN) {
557 PUSH_PRIMAL (p, -1, INT);
558 return;
559 }
560 if (RESULT (file) == NO_PGRESULT) {
561 PUSH_PRIMAL (p, -2, INT);
562 return;
563 }
564 if (!IS_NIL (STRING (file))) {
565 BUFFER str;
566 if (PQresultErrorMessage (RESULT (file)) != NULL) {
567 a68g_bufcpy (str, pq_edit (PQresultErrorMessage (RESULT (file))), BUFFER_SIZE);
568 size_t upb = strlen (str);
569 if (upb > 0 && str[upb - 1] == NEWLINE_CHAR) {
570 str[upb - 1] = NULL_CHAR;
571 }
572 } else {
573 a68g_bufcpy (str, "no error message available", BUFFER_SIZE);
574 }
575 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, str, DEFAULT_WIDTH);
576 STRPOS (file) = 0;
577 PUSH_PRIMAL (p, 0, INT);
578 } else {
579 PUSH_PRIMAL (p, -3, INT);
580 }
581 }
582
583 //! @brief PROC pq db (REF FILE) INT
584
585 void genie_pq_db (NODE_T * p)
586 {
587 A68G_REF ref_file;
588 POP_REF (p, &ref_file);
589 CHECK_REF (p, ref_file, M_REF_FILE);
590 A68G_FILE *file = FILE_DEREF (&ref_file);
591 CHECK_INIT (p, INITIALISED (file), M_FILE);
592 if (CONNECTION (file) == NO_PGCONN) {
593 PUSH_PRIMAL (p, -1, INT);
594 return;
595 }
596 if (!IS_NIL (STRING (file))) {
597 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, PQdb (CONNECTION (file)), DEFAULT_WIDTH);
598 STRPOS (file) = 0;
599 PUSH_PRIMAL (p, 0, INT);
600 } else {
601 PUSH_PRIMAL (p, -3, INT);
602 }
603 }
604
605 //! @brief PROC pq user (REF FILE) INT
606
607 void genie_pq_user (NODE_T * p)
608 {
609 A68G_REF ref_file;
610 POP_REF (p, &ref_file);
611 CHECK_REF (p, ref_file, M_REF_FILE);
612 A68G_FILE *file = FILE_DEREF (&ref_file);
613 CHECK_INIT (p, INITIALISED (file), M_FILE);
614 if (CONNECTION (file) == NO_PGCONN) {
615 PUSH_PRIMAL (p, -1, INT);
616 return;
617 }
618 if (!IS_NIL (STRING (file))) {
619 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, PQuser (CONNECTION (file)), DEFAULT_WIDTH);
620 STRPOS (file) = 0;
621 PUSH_PRIMAL (p, 0, INT);
622 } else {
623 PUSH_PRIMAL (p, -3, INT);
624 }
625 }
626
627 //! @brief PROC pq pass (REF FILE) INT
628
629 void genie_pq_pass (NODE_T * p)
630 {
631 A68G_REF ref_file;
632 POP_REF (p, &ref_file);
633 CHECK_REF (p, ref_file, M_REF_FILE);
634 A68G_FILE *file = FILE_DEREF (&ref_file);
635 CHECK_INIT (p, INITIALISED (file), M_FILE);
636 if (CONNECTION (file) == NO_PGCONN) {
637 PUSH_PRIMAL (p, -1, INT);
638 return;
639 }
640 if (!IS_NIL (STRING (file))) {
641 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, PQpass (CONNECTION (file)), DEFAULT_WIDTH);
642 STRPOS (file) = 0;
643 PUSH_PRIMAL (p, 0, INT);
644 } else {
645 PUSH_PRIMAL (p, -3, INT);
646 }
647 }
648
649 //! @brief PROC pq host (REF FILE) INT
650
651 void genie_pq_host (NODE_T * p)
652 {
653 A68G_REF ref_file;
654 POP_REF (p, &ref_file);
655 CHECK_REF (p, ref_file, M_REF_FILE);
656 A68G_FILE *file = FILE_DEREF (&ref_file);
657 CHECK_INIT (p, INITIALISED (file), M_FILE);
658 if (CONNECTION (file) == NO_PGCONN) {
659 PUSH_PRIMAL (p, -1, INT);
660 return;
661 }
662 if (!IS_NIL (STRING (file))) {
663 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, PQhost (CONNECTION (file)), DEFAULT_WIDTH);
664 STRPOS (file) = 0;
665 PUSH_PRIMAL (p, 0, INT);
666 } else {
667 PUSH_PRIMAL (p, -3, INT);
668 }
669 }
670
671 //! @brief PROC pq port (REF FILE) INT
672
673 void genie_pq_port (NODE_T * p)
674 {
675 A68G_REF ref_file;
676 POP_REF (p, &ref_file);
677 CHECK_REF (p, ref_file, M_REF_FILE);
678 A68G_FILE *file = FILE_DEREF (&ref_file);
679 CHECK_INIT (p, INITIALISED (file), M_FILE);
680 if (CONNECTION (file) == NO_PGCONN) {
681 PUSH_PRIMAL (p, -1, INT);
682 return;
683 }
684 if (!IS_NIL (STRING (file))) {
685 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, PQport (CONNECTION (file)), DEFAULT_WIDTH);
686 STRPOS (file) = 0;
687 PUSH_PRIMAL (p, 0, INT);
688 } else {
689 PUSH_PRIMAL (p, -3, INT);
690 }
691 }
692
693 //! @brief PROC pq tty (REF FILE) INT
694
695 void genie_pq_tty (NODE_T * p)
696 {
697 A68G_REF ref_file;
698 POP_REF (p, &ref_file);
699 CHECK_REF (p, ref_file, M_REF_FILE);
700 A68G_FILE *file = FILE_DEREF (&ref_file);
701 CHECK_INIT (p, INITIALISED (file), M_FILE);
702 if (CONNECTION (file) == NO_PGCONN) {
703 PUSH_PRIMAL (p, -1, INT);
704 return;
705 }
706 if (!IS_NIL (STRING (file))) {
707 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, PQtty (CONNECTION (file)), DEFAULT_WIDTH);
708 STRPOS (file) = 0;
709 PUSH_PRIMAL (p, 0, INT);
710 } else {
711 PUSH_PRIMAL (p, -3, INT);
712 }
713 }
714
715 //! @brief PROC pq options (REF FILE) INT
716
717 void genie_pq_options (NODE_T * p)
718 {
719 A68G_REF ref_file;
720 POP_REF (p, &ref_file);
721 CHECK_REF (p, ref_file, M_REF_FILE);
722 A68G_FILE *file = FILE_DEREF (&ref_file);
723 CHECK_INIT (p, INITIALISED (file), M_FILE);
724 if (CONNECTION (file) == NO_PGCONN) {
725 PUSH_PRIMAL (p, -1, INT);
726 return;
727 }
728 if (!IS_NIL (STRING (file))) {
729 *DEREF (A68G_REF, &STRING (file)) = c_to_a_string (p, PQoptions (CONNECTION (file)), DEFAULT_WIDTH);
730 STRPOS (file) = 0;
731 PUSH_PRIMAL (p, 0, INT);
732 } else {
733 PUSH_PRIMAL (p, -3, INT);
734 }
735 }
736
737 //! @brief PROC pq protocol version (REF FILE) INT
738
739 void genie_pq_protocolversion (NODE_T * p)
740 {
741 A68G_REF ref_file;
742 POP_REF (p, &ref_file);
743 CHECK_REF (p, ref_file, M_REF_FILE);
744 A68G_FILE *file = FILE_DEREF (&ref_file);
745 CHECK_INIT (p, INITIALISED (file), M_FILE);
746 if (CONNECTION (file) == NO_PGCONN) {
747 PUSH_PRIMAL (p, -1, INT);
748 return;
749 }
750 if (!IS_NIL (STRING (file))) {
751 PUSH_PRIMAL (p, PQprotocolVersion (CONNECTION (file)), INT);
752 } else {
753 PUSH_PRIMAL (p, -3, INT);
754 }
755 }
756
757 //! @brief PROC pq server version (REF FILE) INT
758
759 void genie_pq_serverversion (NODE_T * p)
760 {
761 A68G_REF ref_file;
762 POP_REF (p, &ref_file);
763 CHECK_REF (p, ref_file, M_REF_FILE);
764 A68G_FILE *file = FILE_DEREF (&ref_file);
765 CHECK_INIT (p, INITIALISED (file), M_FILE);
766 if (CONNECTION (file) == NO_PGCONN) {
767 PUSH_PRIMAL (p, -1, INT);
768 return;
769 }
770 if (!IS_NIL (STRING (file))) {
771 PUSH_PRIMAL (p, PQserverVersion (CONNECTION (file)), INT);
772 } else {
773 PUSH_PRIMAL (p, -3, INT);
774 }
775 }
776
777 //! @brief PROC pq socket (REF FILE) INT
778
779 void genie_pq_socket (NODE_T * p)
780 {
781 A68G_REF ref_file;
782 POP_REF (p, &ref_file);
783 CHECK_REF (p, ref_file, M_REF_FILE);
784 A68G_FILE *file = FILE_DEREF (&ref_file);
785 CHECK_INIT (p, INITIALISED (file), M_FILE);
786 if (CONNECTION (file) == NO_PGCONN) {
787 PUSH_PRIMAL (p, -1, INT);
788 return;
789 }
790 if (!IS_NIL (STRING (file))) {
791 PUSH_PRIMAL (p, PQsocket (CONNECTION (file)), INT);
792 } else {
793 PUSH_PRIMAL (p, -3, INT);
794 }
795 }
796
797 //! @brief PROC pq backend pid (REF FILE) INT
798
799 void genie_pq_backendpid (NODE_T * p)
800 {
801 A68G_REF ref_file;
802 POP_REF (p, &ref_file);
803 CHECK_REF (p, ref_file, M_REF_FILE);
804 A68G_FILE *file = FILE_DEREF (&ref_file);
805 CHECK_INIT (p, INITIALISED (file), M_FILE);
806 if (CONNECTION (file) == NO_PGCONN) {
807 PUSH_PRIMAL (p, -1, INT);
808 return;
809 }
810 if (!IS_NIL (STRING (file))) {
811 PUSH_PRIMAL (p, PQbackendPID (CONNECTION (file)), INT);
812 } else {
813 PUSH_PRIMAL (p, -3, INT);
814 }
815 }
816
817 #endif
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|