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, &parameter);
 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)