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