home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / lib / libpq / fe-pqexec.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  24.0 KB  |  942 lines

  1. /* ----------------------------------------------------------------
  2.  *   FILE
  3.  *    fe-pqexec.c
  4.  *    
  5.  *   DESCRIPTION
  6.  *    support for executing POSTGRES commands and functions
  7.  *    from a frontend application.
  8.  *
  9.  *   SUPPORT ROUTINES
  10.  *    read_initstr, read_remark, EstablishComm, process_portal,
  11.  *    StringPointerSet
  12.  *
  13.  *   INTERFACE ROUTINES
  14.  *    PQdb         - Return the current database being accessed. 
  15.  *    PQsetdb     - Make the specified database the current database. 
  16.  *    PQreset     - Reset the communication port with the backend. 
  17.  *    PQfinish     - Close communication ports with the backend. 
  18.  *    PQFlushI     - Used for flushing out "poll" queries by the monitor.
  19.  *
  20.  * >>    PQfn         - Send a function call to the POSTGRES backend.
  21.  * >>    PQexec         - Send a query to the POSTGRES backend
  22.  *    
  23.  *   NOTES
  24.  *    These routines are NOT compiled into the postgres backend,
  25.  *    rather they end up in libpq.a.
  26.  *
  27.  *   IDENTIFICATION
  28.  *    $Header: /private/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.27 1992/08/07 00:38:18 mao Exp $
  29.  * ----------------------------------------------------------------
  30.  */
  31.  
  32. #include "tmp/c.h"
  33.  
  34. #include "tmp/simplelists.h"
  35. #include "tmp/libpq-fe.h"
  36. #include "tmp/fastpath.h"
  37. #include "utils/fmgr.h"
  38. #include "utils/exception.h"
  39.  
  40. RcsId ("$Header: /private/postgres/src/lib/libpq/RCS/fe-pqexec.c,v 1.27 1992/08/07 00:38:18 mao Exp $");
  41.  
  42. /* ----------------------------------------------------------------
  43.  * Declare Global Variables.  
  44.  *
  45.  *     The Values of the first four varialbes can be changed by setting
  46.  *    the approriate environment variables.
  47.  *
  48.  *    PQhost:        PGHOST
  49.  *    PQdatabase:    PGDATABASE
  50.  *    PQport:        PGPORT
  51.  *    PQtty:        PGTTY
  52.  * ----------------------------------------------------------------
  53.  */
  54.  
  55. #define DefaultHost    "localhost"
  56. #define DefaultPort    "4321"
  57. #define DefaultTty    "/dev/null"
  58. #define DefaultOption    ""
  59. #define DefaultVacuum    "~/bin/vacuumd"
  60.     
  61. char     *PQhost;        /* the machine on which POSTGRES backend 
  62.                    is running */
  63. char     *PQport = NULL;        /* the communication port with the 
  64.                    POSTGRES backend */
  65. char    *PQtty;            /* the tty on PQhost backend message 
  66.                    is displayed */
  67. char    *PQoption;        /* the optional arguments to POSTGRES 
  68.                    backend */
  69. char     PQdatabase[17] = {0};    /* the POSTGRES database to access */
  70. int     PQportset = 0;        /* 1 if the communication with backend
  71.                    is set */
  72. int    PQxactid = 0;        /* the transaction id of the current 
  73.                    transaction */
  74. /*char    *PQinitstr = NULL;    /* the initialization string passed 
  75.                    to backend (obsolete 2/21/91 -mer) */
  76.  
  77. extern char *getenv();
  78.  
  79. /* ----------------------------------------------------------------
  80.  *            PQ utility routines
  81.  * ----------------------------------------------------------------
  82.  */
  83.  
  84. /* ----------------
  85.  *    read_initstr
  86.  *
  87.  *    This is now a misnomer. PQinistr is no longer used and this routine
  88.  *    really just initializes the PQ global variables if they need it.
  89.  *
  90.  *     Read in the initialization string to be passed to the POSTGRES backend.
  91.  *     The initstr has the format of
  92.  *
  93.  *        USER,DATABASE,TTY,OPTION\n
  94.  *
  95.  *     If the variables do not have values yet, read in the values from the 
  96.  *     environment variables.  If the environment variable does not have a
  97.  *     value, use the default value.
  98.  * ----------------
  99.  */
  100.  
  101. void
  102. read_initstr()
  103. {
  104.     char *envDB;
  105.  
  106.     if (PQdatabase[0] == NULL) 
  107.     {
  108.     if ((envDB = getenv ("PGDATABASE")) == NULL)
  109.         libpq_raise(&ProtocolError,
  110.             form((int)"Fatal Error -- No database is specified."));
  111.     else
  112.     {
  113.         PQdatabase[16] = '\0';
  114.         strncpy(PQdatabase, envDB, 16);
  115.     }
  116.     }
  117.     if ((PQhost == NULL) && ((PQhost = getenv("PGHOST")) == NULL))
  118.     PQhost = DefaultHost;
  119.     
  120.     if ((PQtty == NULL) && ((PQtty = getenv("PGTTY")) == NULL))
  121.     PQtty = DefaultTty;
  122.     
  123.     /*
  124.      *  As of release 4, PQoption is no longer taken from the environment
  125.      *  var PGOPTION if it's not already defined.  This change was made
  126.      *  in order to be consistent with the documentation and to make frew
  127.      *  happy.
  128.      *
  129.      *  In general, users shouldn't be screwing around with PQoption, in
  130.      *  any case.
  131.      */
  132.  
  133.     if (PQoption == NULL)
  134.     PQoption = DefaultOption;
  135.     
  136.     if (PQport == NULL) {
  137.     if (getenv("PGPORT") == NULL)
  138.        PQport = DefaultPort;
  139.     else PQport = getenv("PGPORT");
  140.     }
  141.  
  142. /* The function of PQinitstr is now done via a message to the postmaster
  143.  *
  144.  *  PQinitstr = addValues(initstr_length);
  145.  *  
  146.  *  sprintf(PQinitstr, "%s,%s,%s,%s\n",
  147.  *        getenv("USER"), PQdatabase, PQtty, PQoption);
  148.  */
  149. }
  150.  
  151. /* ----------------
  152.  *    read_remark - Read and discard remarks. 
  153.  * ----------------
  154.  */
  155. void
  156. read_remark(id)
  157.     char id[];
  158. {
  159.     char remarks[remark_length];
  160.     char errormsg[error_msg_length];
  161.  
  162.     while (id[0] == 'R') {
  163.     pq_getstr(remarks, remark_length);
  164.     if (pq_getnchar(id, 0, 1) == EOF) 
  165.        return;
  166.     }
  167.     while(id[0] == 'N') {
  168.         pq_getstr(errormsg,error_msg_length);
  169.         fprintf(stderr,"%s",&errormsg[0]+4);
  170.         if (pq_getnchar(id, 0, 1) == EOF)
  171.        return;
  172.     }
  173. }
  174.  
  175. /* ----------------
  176.  *    EstablishComm
  177.  * ----------------
  178.  */
  179. static
  180. void
  181. EstablishComm()
  182. {
  183.     if (!PQportset) { 
  184.     read_initstr();
  185.  
  186.     if (pq_connect(PQdatabase, getenv("USER"), PQoption, PQhost, PQtty,
  187.             (char *) NULL, (short)atoi(PQport) ) == -1 ) {
  188.         libpq_raise(&ProtocolError,
  189.           form((int)"Failed to connect to backend (host=%s, port=%s)",
  190.            PQhost, PQport));
  191.     }
  192.  
  193.     pq_flush();
  194.     PQportset = 1;
  195.     }
  196. }
  197.  
  198. /* ----------------
  199.  *    process_portal
  200.  *    
  201.  *     Process portal queries. 
  202.  *     Return values are the same as PQexec().
  203.  * ----------------
  204.  */
  205.  
  206. char *
  207. process_portal(rule_p)
  208.     int rule_p;
  209. {
  210.     char pname[portal_name_length];
  211.     char id[2];
  212.     char errormsg[error_msg_length];
  213.     char command[command_length];
  214.     char PQcommand[portal_name_length+1];
  215.     static char retbuf[portal_name_length + 1];
  216.  
  217.     /* Read in the portal name. */
  218.     pq_getstr(pname, portal_name_length);
  219.     pqdebug("Portal name = %s", pname);
  220.  
  221.     /*
  222.      * This for loop is necessary so that NOTICES out of portal processing
  223.      * stuff are handled properly.
  224.      */
  225.  
  226.     for (;;) {
  227.         /* Read in the identifier following the portal name. */
  228.         pq_getnchar(id, 0, 1);
  229.         read_remark(id);
  230.         pqdebug("Identifier is: %c", (char *)id[0]);
  231.  
  232.         switch (id[0]) {
  233.         case 'E':
  234.         /* An error, return 0. */
  235.         pq_getstr(errormsg, error_msg_length);
  236.         pqdebug("%s error encountered.", errormsg);
  237.         /* get past gunk at front of errmsg */
  238.         fprintf(stderr,"%s", &errormsg[0] + 4);
  239.         strcpy(retbuf, "R");
  240.         return(retbuf);
  241.  
  242.         case 'N': /* print notice and go back to processing return values */
  243.         /*
  244.          * If we get an EOF (i.e. backend quickdies) return an R to the fe
  245.          */
  246.         if (pq_getstr(errormsg, error_msg_length) == EOF)
  247.         return ("R");
  248.         pqdebug("%s notice encountered.", errormsg);
  249.         /* get past gunk at front of errmsg */
  250.         fprintf(stderr,"%s", &errormsg[0] + 4);
  251.         break;
  252.         
  253.         case 'T':
  254.         /* Tuples are returned, dump data into a portal buffer. */
  255.         if (dump_data(pname, rule_p) == -1)
  256.         {
  257.             return("R");
  258.         }
  259.         sprintf(PQcommand, "P%s", pname);
  260.         strcpy(retbuf, PQcommand);
  261.         return(retbuf);
  262.     
  263.         /* Pending data inquiry - return nothing */
  264.         case 'C':
  265.         /*
  266.          * Portal query command (e.g., retrieve, close),
  267.          * no tuple returned.
  268.          */
  269.         PQxactid = pq_getint (4);
  270.         pqdebug("Transaction Id is: %d", (char *)PQxactid);
  271.         pq_getstr(command, command_length);
  272.         pqdebug("Query command: %s", command);
  273.     
  274.         /* Process the portal commands. */
  275.         if (strcmp(command, "retrieve") == 0) {
  276.             /* Allocate a portal buffer, if portal table is full, error. */
  277.             pbuf_setup(pname);
  278.             return
  279.             "Cretrieve";
  280.         } 
  281.         else if (strcmp (command, "close") == 0) 
  282.             return
  283.             "Cclose";
  284.         else {
  285.             sprintf(retbuf, "C%s", command);
  286.             return
  287.             retbuf;
  288.         }
  289.  
  290.         default:
  291.         {
  292.             char s[45];
  293.  
  294.             PQreset();
  295.             sprintf(s, "Unexpected identifier in process_portal: %c", id[0]);
  296.             libpq_raise(&ProtocolError, form ((int)s));
  297.         }
  298.     }
  299.     }
  300. }
  301.  
  302. /* ----------------
  303.  *    StringPointerSet
  304.  * ----------------
  305.  */
  306. static
  307. void
  308. StringPointerSet(stringInOutP, newString, environmentString, defaultString)
  309.     String    *stringInOutP;
  310.     String    newString;
  311.     String    environmentString;
  312.     String    defaultString;
  313. {
  314.     Assert(PointerIsValid(stringInOutP));
  315.     Assert(!PointerIsValid(*stringInOutP));
  316.     Assert(PointerIsValid(environmentString));
  317.     
  318.     if (PointerIsValid(newString)) {
  319.     *stringInOutP = newString;
  320.     } else {
  321.     *stringInOutP = getenv(environmentString);
  322.     
  323.     if (!PointerIsValid(*stringInOutP)) {
  324.         *stringInOutP = defaultString;
  325.     }
  326.     }
  327. }
  328.  
  329. /* ----------------------------------------------------------------
  330.  *            PQ interface routines
  331.  * ----------------------------------------------------------------
  332.  */
  333.  
  334. /* --------------------------------
  335.  *    PQdb - Return the current database being accessed. 
  336.  * --------------------------------
  337.  */
  338. char *
  339. PQdb()
  340. {
  341.     return PQdatabase;
  342. }
  343.  
  344. /* ----------------
  345.  *    PQsetdb - Make the specified database the current database. 
  346.  * ----------------
  347.  */
  348. void
  349. PQsetdb(dbname)
  350.     char *dbname;
  351. {
  352.     PQreset();
  353.     PQdatabase[16] = '\0';
  354.     strncpy(PQdatabase, dbname, 16);
  355. }
  356.  
  357. /* ----------------
  358.  *    PQreset - Reset the communication port with the backend. 
  359.  * ----------------
  360.  */
  361. void
  362. PQreset()
  363. {
  364.     pq_close();
  365.     PQportset = 0;
  366. /*
  367.  *  if (PQinitstr != NULL)
  368.  *      pq_free(PQinitstr);
  369.  *
  370.  *  PQinitstr = NULL;
  371.  */
  372. }
  373.  
  374. /* ----------------
  375.  *    PQfinish - Close communication ports with the backend. 
  376.  * ----------------
  377.  */
  378. void
  379. PQfinish()
  380. {
  381.     if (!PQportset)
  382.     return;
  383.     
  384.     pq_putnchar("X", 1);    /* exiting */
  385.     pq_flush();
  386.     pq_close();
  387.  
  388.     PQportset = 0;
  389. }
  390.  
  391. /* ----------------
  392.  *    PQFlushI - Used for flushing out "poll" queries by the monitor.
  393.  * ----------------
  394.  */
  395. int
  396. PQFlushI(i_count)
  397.     int i_count;
  398. {
  399.     int i;
  400.     char holder[1];
  401.  
  402.     for (i = 0; i < i_count; i++) {
  403.     pq_getnchar(holder, 0, 1);
  404.     if (holder[0] != 'I')
  405.         fprintf(stderr, "PQFlushI: read bad protocol entity");
  406.     pq_getint(4); /* throw this away */
  407.     }
  408. }
  409.  
  410. /* ----------------
  411.  *    PQfn -  Send a function call to the POSTGRES backend.
  412.  *
  413.  *    fnid        : function id
  414.  *     result_buf      : pointer to result buffer (&int if integer)
  415.  *     result_len    : length of return value.
  416.  *      actual_result_len: actual length returned. (differs from result_len for
  417.  *                      varlena structures.
  418.  *      result_type     : If the result is an integer, this must be 1,
  419.  *                        If result is opaque, this must be 2.
  420.  *     args        : pointer to a NULL terminated arg array.
  421.  *              (length, if integer, and result-pointer)
  422.  *     nargs        : # of arguments in args array.
  423.  * ----------------
  424.  */
  425. char *
  426. PQfn(fnid, result_buf, result_len, actual_result_len,
  427.      result_type, args, nargs)
  428.     int fnid;
  429.     int *result_buf;    /* can't use void, dec compiler barfs */
  430.     int result_len;
  431.      int *actual_result_len;
  432.     int result_type;
  433.     PQArgBlock *args;
  434.     int nargs;
  435. {
  436.     char id[2];
  437.     char errormsg[error_msg_length];
  438.     char command[command_length];
  439.     char PQcommand[command_length+1];
  440.     void EstablishComm();
  441.     int  actual_len;
  442.     short i;
  443.  
  444.     if (!PQportset)
  445.     EstablishComm();
  446.     
  447.     pq_putnchar("F", 1);    /*    function        */
  448.     pq_putint(PQxactid, 4);    /*    transaction id ?    */
  449.     pq_putint(fnid, 4);        /*    function id        */
  450.     pq_putint(result_len, 4);    /*    length of return value  */
  451.     pq_putint(nargs, 4);    /*    # of args        */
  452.     
  453.     for (i=0; i < nargs; ++i) { /*    len.int4 + contents    */
  454.     pq_putint(args[i].len, 4);
  455.     if (args[i].isint)
  456.       pq_putint(args[i].u.integer, 4);
  457.     else if (args[i].len == VAR_LENGTH_ARG) {
  458.             pq_putstr((char *)args[i].u.ptr);
  459.     } else
  460.         pq_putnchar((char *)args[i].u.ptr, args[i].len);
  461.     }
  462.  
  463.     pq_flush();
  464.  
  465.     /* process return value from the backend    */
  466.  
  467.     id[0] = '?';
  468.  
  469.     pq_getnchar(id, 0, 1);
  470.     while (id[0] == 'E') {
  471.     int len;
  472.         char buf[1024];
  473.  
  474.     if ((len = pq_getint(4)) >= sizeof(buf))
  475.         len = sizeof(buf) - 1;
  476.     pq_getstr(buf,len);
  477.  
  478.     fprintf(stderr, "Error: %s",buf);
  479.     if (pq_getnchar(id, 0, 1) == EOF)
  480.         return ((char *) NULL);
  481.     }
  482.  
  483.     read_remark(id);
  484.     fnid = pq_getint(4);
  485.     pqdebug("The Identifier is: %c", (char *)id[0]);
  486.     
  487.     /* Read in the transaction id. */
  488.     pqdebug("The Transaction Id is: %d", (char *)PQxactid);
  489.  
  490.     if (id[0] == 'V')
  491.     pq_getnchar(id, 0, 1);
  492.     for (;;) {
  493.     switch (id[0]) {
  494.       case 'G':        /* PQFN: simple return value    */
  495.         actual_len = pq_getint(4);
  496.         pqdebug2("LENGTH act/usr %ld/%ld\n", (char*)actual_len, (char*)result_len);
  497.         if ((actual_len != VAR_LENGTH_RESULT) &&
  498.                 (actual_len < 0 || actual_len > result_len)) {
  499.         pqdebug("RESET CALLED FROM CASE G", (char *)0);
  500.         PQreset();
  501.         libpq_raise(&ProtocolError, form ((int)"Buffer Too Small: %s", id));
  502.         }
  503.         if (result_type == 1)
  504.           *(int *)result_buf = pq_getint(4);
  505.         else if (actual_len == VAR_LENGTH_RESULT) {
  506.         pq_getstr((char *)result_buf,MAX_STRING_LENGTH);
  507.         } else
  508.           pq_getnchar((char *)result_buf, 0, actual_len);
  509.         if (actual_result_len != NULL)
  510.           *actual_result_len = actual_len;
  511.         if ((result_type != 2) && /* not a binary result */
  512.         (actual_len != result_len)) /* if wouldn't overflow the buf */
  513.           ((char *)result_buf)[actual_len] = 0; /* add a \0 */
  514.         pq_getnchar(id, 0, 1);
  515.         return("G");
  516.         
  517.       case 'E':        /* print error and go back to processing return values */
  518.         pq_getstr(errormsg, error_msg_length);
  519.         pqdebug("%s error encountered.", errormsg);
  520.         fprintf(stderr,"%s", errormsg);
  521.         if (pq_getnchar(id, 0, 1) == EOF)
  522.         return((char *) NULL);
  523.         break;
  524.  
  525.       case 'N':        /* print notice and go back to processing return values */
  526.         pq_getstr(errormsg, error_msg_length);
  527.         pqdebug("%s notice encountered.", errormsg);
  528.         fprintf(stderr,"%s", errormsg);
  529.         pq_getnchar(id, 0, 1);
  530.         if (pq_getnchar(id, 0, 1) == EOF)
  531.         return((char *) NULL);
  532.         break;
  533.  
  534.       case '0':        /* PQFN: no return value    */
  535.         return("V");
  536.  
  537.         default:
  538.         /* The backend violates the protocol. */
  539.         pqdebug("RESET CALLED FROM CASE G", (char *)0);
  540.         pqdebug("Protocol Error, bad form, got '%c'", (char *)id[0]);
  541.         PQreset();
  542.         libpq_raise(&ProtocolError, form((int)"Unexpected identifier: %s", id));
  543.         return(NULL);
  544.     }
  545.     }
  546. }
  547.  
  548. /*
  549.  *  PQfsread, PQfswrite -- special-purpose versions of PQfn for file
  550.  *               system (POSTGRES large object) read and
  551.  *               write routines.
  552.  *
  553.  *    We need these special versions because the user expects a standard
  554.  *    unix file system interface, and postgres wants to use varlenas
  555.  *    all over the place.
  556.  */
  557.  
  558. int
  559. PQfsread(fd, buf, nbytes)
  560.     int fd;
  561.     char *buf;
  562.     int nbytes;
  563. {
  564.     int fnid;
  565.     char id[2];
  566.     char errormsg[error_msg_length];
  567.     char command[command_length];
  568.     char PQcommand[command_length+1];
  569.     void EstablishComm();
  570.     int  actual_len;
  571.     short i;
  572.  
  573.     if (!PQportset)
  574.     EstablishComm();
  575.     
  576.     pq_putnchar("F", 1);    /* function */
  577.     pq_putint(PQxactid, 4);    /* transaction id? */
  578.     pq_putint(F_LOREAD, 4);    /* function id */
  579.  
  580.     /* size of return value -- += sizeof(int) because we expect a varlena */
  581.     pq_putint(nbytes + sizeof(int), 4);
  582.  
  583.     pq_putint(2, 4);        /* nargs */
  584.  
  585.     /* now put arguments */
  586.     pq_putint(4, 4);        /* length of fd */
  587.     pq_putint(fd, 4);
  588.  
  589.     pq_putint(4, 4);        /* length of nbytes */
  590.     pq_putint(nbytes, 4);
  591.  
  592.     pq_flush();
  593.  
  594.     /* process return value from the backend    */
  595.  
  596.     id[0] = '?';
  597.  
  598.     pq_getnchar(id, 0, 1);
  599.     while (id[0] == 'E') {
  600.     int len;
  601.         char buf[1024];
  602.  
  603.     if ((len = pq_getint(4)) >= sizeof(buf))
  604.         len = sizeof(buf) - 1;
  605.     pq_getstr(buf,len);
  606.  
  607.     fprintf(stderr, "Error: %s",buf);
  608.     if (pq_getnchar(id, 0, 1) == EOF)
  609.         return (-1);
  610.     }
  611.  
  612.     read_remark(id);
  613.     fnid = pq_getint(4);
  614.     pqdebug("The Identifier is: %c", (char *)id[0]);
  615.     
  616.     /* Read in the transaction id. */
  617.     pqdebug("The Transaction Id is: %d", (char *)PQxactid);
  618.  
  619.     if (id[0] == 'V')
  620.     pq_getnchar(id, 0, 1);
  621.     for (;;) {
  622.     switch (id[0]) {
  623.       case 'G':
  624.  
  625.         /*
  626.          *  We know exactly what the return stream looks like, here:
  627.          *  it's a length, followed by a varlena (which includes the
  628.          *  length again...).
  629.          */
  630.  
  631.         nbytes = actual_len = pq_getint(4);
  632. #if 0        
  633.     /* fe/be does NOT transmit varlenas this way */
  634.         nbytes = pq_getint(4);
  635.         nbytes -= sizeof(long);    /* compensate for varlena vl->len */
  636. #endif
  637.  
  638.         if (nbytes > 0)
  639.         pq_getnchar((char *)buf, 0, nbytes);
  640.         pq_getnchar(id, 0, 1);
  641.         return(nbytes);
  642.         
  643.       case 'E':        /* print error and go back to processing return values */
  644.         pq_getstr(errormsg, error_msg_length);
  645.         pqdebug("%s error encountered.", errormsg);
  646.         fprintf(stderr,"%s", errormsg);
  647.         pq_getnchar(id, 0, 1);
  648.         break;
  649.  
  650.       case 'N':        /* print notice and go back to processing return values */
  651.         pq_getstr(errormsg, error_msg_length);
  652.         pqdebug("%s notice encountered.", errormsg);
  653.         fprintf(stderr,"%s", errormsg);
  654.         pq_getnchar(id, 0, 1);
  655.         break;
  656.  
  657.       default:
  658.         /* The backend violates the protocol. */
  659.         pqdebug("RESET CALLED FROM CASE G", (char *)0);
  660.         pqdebug("Protocol Error, bad form, got '%c'", (char *)id[0]);
  661.         PQreset();
  662.         libpq_raise(&ProtocolError, form((int)"Unexpected identifier: %s", id));
  663.         return(-1);
  664.     }
  665.     }
  666. }
  667.  
  668. int
  669. PQfswrite(fd, buf, nbytes)
  670.     int fd;
  671.     char *buf;
  672.     int nbytes;
  673. {
  674.     int fnid;
  675.     char id[2];
  676.     char errormsg[error_msg_length];
  677.     char command[command_length];
  678.     char PQcommand[command_length+1];
  679.     void EstablishComm();
  680.     int  actual_len;
  681.     short i;
  682.  
  683.     if (!PQportset)
  684.     EstablishComm();
  685.     
  686.     pq_putnchar("F", 1);    /*    function        */
  687.     pq_putint(PQxactid, 4);    /*    transaction id ?    */
  688.     pq_putint(F_LOWRITE, 4);    /*    function id        */
  689.     pq_putint(4, 4);        /*    length of return value  */
  690.     pq_putint(2, 4);        /*    # of args        */
  691.     
  692.     /* now put arguments */
  693.     pq_putint(4, 4);        /* size of fd */
  694.     pq_putint(fd, 4);
  695. /*
  696. * The method of transmitting varlenas is:
  697. * Send vl_len-4
  698. * Send data consisting of vl_len-4 bytes.
  699. */
  700.     pq_putint(nbytes, 4);    /* size of varlena */
  701. #if 0
  702.     /* The fe/be protocol does NOT transmit varlenas this way */
  703.     pq_putint(nbytes + 4, 4);    /* vl_len */
  704. #endif
  705.     pq_putnchar(buf, nbytes);    /* vl_dat */
  706.  
  707.     pq_flush();
  708.  
  709.     /* process return value from the backend    */
  710.     id[0] = '?';
  711.  
  712.     pq_getnchar(id, 0, 1);
  713.     while (id[0] == 'E') {
  714.     int len;
  715.         char buf[1024];
  716.  
  717.     if ((len = pq_getint(4)) >= sizeof(buf))
  718.         len = sizeof(buf) - 1;
  719.     pq_getstr(buf,len);
  720.  
  721.     fprintf(stderr, "Error: %s",buf);
  722.     if (pq_getnchar(id, 0, 1) == EOF)
  723.         return (-1);
  724.     }
  725.  
  726.     read_remark(id);
  727.     fnid = pq_getint(4);
  728.     pqdebug("The Identifier is: %c", (char *)id[0]);
  729.     
  730.     /* Read in the transaction id. */
  731.     pqdebug("The Transaction Id is: %d", (char *)PQxactid);
  732.  
  733.     if (id[0] == 'V')
  734.     pq_getnchar(id, 0, 1);
  735.  
  736.     for (;;) {
  737.     switch (id[0]) {
  738.       case 'G':        /* PQFN: simple return value    */
  739.         actual_len = pq_getint(4);
  740.         if (actual_len != 4)
  741.         libpq_raise(&ProtocolError,
  742.                 form((int) "wanted 4 bytes in PQfswrite, got %d\n",
  743.                 actual_len));
  744.         nbytes = pq_getint(4);
  745.         pq_getnchar(id, 0, 1);
  746.         return (nbytes);
  747.         
  748.       case 'E': /* print error and go back to processing return values */
  749.         pq_getstr(errormsg, error_msg_length);
  750.         pqdebug("%s error encountered.", errormsg);
  751.         fprintf(stderr,"%s", errormsg);
  752.         pq_getnchar(id, 0, 1);
  753.         break;
  754.  
  755.       case 'N': /* print notice and go back to processing return values */
  756.         pq_getstr(errormsg, error_msg_length);
  757.         pqdebug("%s notice encountered.", errormsg);
  758.         fprintf(stderr,"%s", errormsg);
  759.         pq_getnchar(id, 0, 1);
  760.         break;
  761.  
  762.         default:
  763.         /* The backend violates the protocol. */
  764.         pqdebug("RESET CALLED FROM CASE G", (char *)0);
  765.         pqdebug("Protocol Error, bad form, got '%c'", (char *)id[0]);
  766.         PQreset();
  767.         libpq_raise(&ProtocolError, form((int)"Unexpected identifier: %s", id));
  768.         return(NULL);
  769.     }
  770.     }
  771. }
  772.  
  773. /* ----------------
  774.  *    PQexec -  Send a query to the POSTGRES backend
  775.  *
  776.  *     The return value is a string.  
  777.  *     If there is an error: return "E error-message".
  778.  *     If tuples are fetched from the backend, return "P portal-name".
  779.  *     If a query is executed successfully but no tuples fetched, 
  780.  *     return "C query-command".
  781.  * ----------------
  782.  */
  783.  
  784. char *
  785. PQexec(query)
  786.     char *query;
  787. {
  788.     char id[2];
  789.     char errormsg[error_msg_length];
  790.     char command[command_length];
  791.     char PQcommand[command_length+1];
  792.     void EstablishComm();
  793.  
  794.     /* If the communication is not established, establish it. */
  795.     if (!PQportset)
  796.     EstablishComm();
  797.  
  798.     /* Send a query to backend. */
  799.     pq_putnchar("Q", 1);
  800.     pq_putint(PQxactid, 4);
  801.     pq_putstr(query);
  802.     pqdebug("The query sent to the backend: %s", query);
  803.     pq_flush();
  804.  
  805.     /* forever (or at least until we get something besides a notice) */
  806.     for (;;) {  
  807.  
  808.         /* Process return values from the backend. 
  809.      * The code in this function is the implementation of
  810.      * the communication protocol.
  811.      */
  812.         id[0] = '?';
  813.  
  814.         /* Get the identifier. */
  815.         pq_getnchar(id,0,1); 
  816.  
  817.         read_remark(id);
  818.         pqdebug("The Identifier is: %c", (char *)id[0]);
  819.  
  820.         /* Read in the transaction id. */
  821.         PQxactid = pq_getint(4);
  822.         pqdebug("The Transaction Id is: %d", (char *)PQxactid);
  823.  
  824.         switch (id[0]) {
  825.         case 'I':
  826.         return("I");
  827.         
  828.         case 'E':
  829.         /* An error, return 0. */
  830.         pq_getstr(errormsg, error_msg_length);
  831.         pqdebug("%s error encountered.", errormsg);
  832.         fprintf(stderr,"%s", errormsg);
  833.         /* PQportset = 0;
  834.            EstablishComm(); */
  835.         return("R");
  836.         
  837.         case 'N': /* print notice and go back to processing return values */
  838.         /*
  839.          * If we get an EOF (i.e. backend quickdies) return an R to the fe
  840.          */
  841.         if (pq_getstr(errormsg, error_msg_length) == EOF)
  842.         return ("R");
  843.         pqdebug("%s notice encountered.", errormsg);
  844.         fprintf(stderr,"%s", errormsg);
  845.         break;
  846.  
  847.         case 'A': {
  848.         char relname[16];
  849.         extern int PQAsyncNotifyWaiting;
  850.         int pid;
  851.         PQAsyncNotifyWaiting = 0;
  852.         
  853.         /* Asynchronized portal. */
  854.         /* No tuple transfer at this stage. */
  855.         pqdebug("%s portal encountered.", "Asynchronized");
  856.         /* Processed the same way as synchronized portal. */
  857. /*        return
  858.         process_portal(1);*/
  859.         pq_getstr(relname,16);
  860.         pid =pq_getint(4);
  861.         PQappendNotify(relname,pid);
  862.     }
  863.         break;
  864.         case 'P':
  865.         /* Synchronized (normal) portal. */
  866.         return
  867.         process_portal(0);
  868.         
  869.         case 'C':
  870.         /* Query executed successfully. */
  871.         pq_getstr (command, command_length);
  872.         pqdebug ("Query command: %s", command);
  873.         sprintf (PQcommand, "C%s", command);
  874.         return
  875.         PQcommand;
  876.  
  877.     case 'B':
  878.         /* Copy command began successfully - it is sending stuff back...  */
  879.         return "BCOPY";
  880.  
  881.     case 'D':
  882.         /* Copy command began successfully - it is waiting to receive... */
  883.         return "DCOPY";
  884.  
  885.         default:
  886.         /* The backend violates the protocol. */
  887.         if (id[0] == '?')
  888.             libpq_raise(&ProtocolError, 
  889.             form((int)"No response from the backend, exiting...\n"));
  890.         else
  891.             libpq_raise(&ProtocolError, 
  892.            form((int)"Unexpected response from the backend, exiting...\n"));
  893.         exit(1);
  894.         }
  895.     }
  896. }
  897.  
  898. int
  899. PQendcopy()
  900.  
  901. {
  902.     char id[2];
  903.     char errormsg[error_msg_length];
  904.  
  905.     for (;;) 
  906.     {
  907.         id[0] = '?';
  908.  
  909.         pq_getnchar(id,0,1); 
  910.  
  911.         switch(id[0])
  912.         {
  913.             case 'N':
  914.  
  915.                 pq_getstr(errormsg, error_msg_length);
  916.                 pqdebug("%s notice encountered.", errormsg);
  917.                 fprintf(stderr,"%s", errormsg);
  918.                 break;
  919.  
  920.             case 'E':
  921.  
  922.                 pq_getstr(errormsg, error_msg_length);
  923.                 pqdebug("%s notice encountered.", errormsg);
  924.                 fprintf(stderr,"%s", errormsg);
  925.                 return(0);
  926.  
  927.             case 'Z': /* backend finished the copy */
  928.                 return(1);
  929.  
  930.             default:
  931.                 /* The backend violates the protocol. */
  932.                 if (id[0] == '?')
  933.                     libpq_raise(&ProtocolError, 
  934.                         form((int)"No response from the backend, exiting...\n"));
  935.                 else
  936.                     libpq_raise(&ProtocolError, 
  937.                     form((int)"Unexpected response from the backend, exiting...\n"));
  938.                 exit(1);
  939.         }
  940.     }
  941. }
  942.