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