7
7
*
8
8
*
9
9
* IDENTIFICATION
10
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.25 1996/12/28 01:57:13 momjian Exp $
10
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.26 1996/12/31 07:29:15 bryanh Exp $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
@@ -348,6 +348,170 @@ makePGresult(PGconn* conn, char* pname)
348
348
}
349
349
350
350
351
+ /*
352
+ * Assuming that we just sent a query to the backend, read the backend's
353
+ * response from stream <pfin> and respond accordingly.
354
+ *
355
+ * If <pfdebug> is non-null, write to that stream whatever we receive
356
+ * (it's a debugging trace).
357
+ *
358
+ * Return as <result> a pointer to a proper final PGresult structure,
359
+ * newly allocated, for the query based on the response we get. If the
360
+ * response we get indicates that the query didn't execute, return a
361
+ * null pointer and don't allocate any space, but also place a text
362
+ * string explaining the problem at <*reason>.
363
+ */
364
+
365
+ static void
366
+ process_response_from_backend (FILE * pfin , FILE * pfout , FILE * pfdebug ,
367
+ PGconn * conn ,
368
+ PGresult * * result_p , char * const reason ) {
369
+
370
+ char id ;
371
+ /* The protocol character received from the backend. The protocol
372
+ character is the first character in the backend's response to our
373
+ query. It defines the nature of the response.
374
+ */
375
+ PGnotify * newNotify ;
376
+ bool done ;
377
+ /* We're all done with the query and ready to return the result. */
378
+ int emptiesSent ;
379
+ /* Number of empty queries we have sent in order to flush out multiple
380
+ responses, less the number of corresponding responses we have
381
+ received.
382
+ */
383
+ char cmdStatus [MAX_MESSAGE_LEN ];
384
+ char pname [MAX_MESSAGE_LEN ]; /* portal name */
385
+
386
+ /* loop because multiple messages, especially NOTICES,
387
+ can come back from the backend. NOTICES are output directly to stderr
388
+ */
389
+
390
+ emptiesSent = 0 ; /* No empty queries sent yet */
391
+ pname [0 ] = '\0' ;
392
+
393
+ done = false; /* initial value */
394
+ while (!done ) {
395
+ /* read the result id */
396
+ id = pqGetc (pfin , pfdebug );
397
+ if (id == EOF ) {
398
+ /* hmm, no response from the backend-end, that's bad */
399
+ (void ) sprintf (reason ,
400
+ "PQexec() -- Request was sent to backend, but backend "
401
+ "closed the channel before "
402
+ "responding. This probably means the backend "
403
+ "terminated abnormally before or while processing "
404
+ "the request.\n" );
405
+ conn -> status = CONNECTION_BAD ; /* No more connection to backend */
406
+ * result_p = (PGresult * )NULL ;
407
+ done = true;
408
+ } else {
409
+ switch (id ) {
410
+ case 'A' :
411
+ newNotify = (PGnotify * )malloc (sizeof (PGnotify ));
412
+ pqGetInt (& (newNotify -> be_pid ), 4 , pfin , pfdebug );
413
+ pqGets (newNotify -> relname , NAMEDATALEN , pfin , pfdebug );
414
+ DLAddTail (conn -> notifyList , DLNewElem (newNotify ));
415
+ /* async messages are piggy'ed back on other messages,
416
+ so we stay in the while loop for other messages */
417
+ break ;
418
+ case 'C' : /* portal query command, no rows returned */
419
+ if (pqGets (cmdStatus , MAX_MESSAGE_LEN , pfin , pfdebug ) == 1 ) {
420
+ sprintf (reason ,
421
+ "PQexec() -- query command completed, "
422
+ "but return message from backend cannot be read." );
423
+ * result_p = (PGresult * )NULL ;
424
+ done = true;
425
+ } else {
426
+ /*
427
+ // since backend may produce more than one result for some
428
+ // commands need to poll until clear
429
+ // send an empty query down, and keep reading out of the pipe
430
+ // until an 'I' is received.
431
+ */
432
+ pqPuts ("Q " , pfout , pfdebug ); /* send an empty query */
433
+ /*
434
+ * Increment a flag and process messages in the usual way because
435
+ * there may be async notifications pending. DZ - 31-8-1996
436
+ */
437
+ emptiesSent ++ ;
438
+ }
439
+ break ;
440
+ case 'E' : /* error return */
441
+ if (pqGets (conn -> errorMessage , ERROR_MSG_LENGTH , pfin , pfdebug ) == 1 ) {
442
+ (void ) sprintf (reason ,
443
+ "PQexec() -- error return detected from backend, "
444
+ "but attempt to read the error message failed." );
445
+ }
446
+ * result_p = (PGresult * )NULL ;
447
+ done = true;
448
+ break ;
449
+ case 'I' : { /* empty query */
450
+ /* read and throw away the closing '\0' */
451
+ int c ;
452
+ if ((c = pqGetc (pfin ,pfdebug )) != '\0' ) {
453
+ fprintf (stderr ,"error!, unexpected character %c following 'I'\n" , c );
454
+ }
455
+ if (emptiesSent ) {
456
+ if (-- emptiesSent == 0 ) { /* is this the last one? */
457
+ /*
458
+ * If this is the result of a portal query command set the
459
+ * command status and message accordingly. DZ - 31-8-1996
460
+ */
461
+ * result_p = makeEmptyPGresult (conn ,PGRES_COMMAND_OK );
462
+ strncpy ((* result_p )-> cmdStatus , cmdStatus , CMDSTATUS_LEN - 1 );
463
+ done = true;
464
+ }
465
+ }
466
+ else {
467
+ * result_p = makeEmptyPGresult (conn , PGRES_EMPTY_QUERY );
468
+ done = true;
469
+ }
470
+ }
471
+ break ;
472
+ case 'N' : /* notices from the backend */
473
+ if (pqGets (reason , ERROR_MSG_LENGTH , pfin , pfdebug ) == 1 ) {
474
+ sprintf (reason ,
475
+ "PQexec() -- Notice detected from backend, "
476
+ "but attempt to read the notice failed." );
477
+ * result_p = (PGresult * )NULL ;
478
+ done = true;
479
+ } else
480
+ /* Should we really be doing this? These notices are not important
481
+ enough for us to presume to put them on stderr. Maybe the caller
482
+ should decide whether to put them on stderr or not. BJH 96.12.27
483
+ */
484
+ fprintf (stderr ,"%s" , reason );
485
+ break ;
486
+ case 'P' : /* synchronous (normal) portal */
487
+ pqGets (pname , MAX_MESSAGE_LEN , pfin , pfdebug ); /* read in portal name*/
488
+ break ;
489
+ case 'T' : /* actual row results: */
490
+ * result_p = makePGresult (conn , pname );
491
+ done = true;
492
+ break ;
493
+ case 'D' : /* copy command began successfully */
494
+ * result_p = makeEmptyPGresult (conn , PGRES_COPY_IN );
495
+ done = true;
496
+ break ;
497
+ case 'B' : /* copy command began successfully */
498
+ * result_p = makeEmptyPGresult (conn , PGRES_COPY_OUT );
499
+ done = true;
500
+ break ;
501
+ default :
502
+ sprintf (reason ,
503
+ "unknown protocol character '%c' read from backend. "
504
+ "(The protocol character is the first character the "
505
+ "backend sends in response to a query it receives).\n" ,
506
+ id );
507
+ * result_p = (PGresult * )NULL ;
508
+ done = true;
509
+ } /* switch on protocol character */
510
+ } /* if character was received */
511
+ } /* while not done */
512
+ }
513
+
514
+
351
515
352
516
/*
353
517
* PQexec
@@ -364,27 +528,14 @@ PGresult*
364
528
PQexec (PGconn * conn , const char * query )
365
529
{
366
530
PGresult * result ;
367
- int id ;
368
531
char buffer [MAX_MESSAGE_LEN ];
369
- char cmdStatus [MAX_MESSAGE_LEN ];
370
- char pname [MAX_MESSAGE_LEN ]; /* portal name */
371
- PGnotify * newNotify ;
372
- FILE * pfin , * pfout , * pfdebug ;
373
- static int emptiesPending = 0 ;
374
- bool emptySent = false;
375
-
376
- pname [0 ]= '\0' ;
377
532
378
533
if (!conn ) return NULL ;
379
534
if (!query ) {
380
535
sprintf (conn -> errorMessage , "PQexec() -- query pointer is null." );
381
536
return NULL ;
382
537
}
383
538
384
- pfin = conn -> Pfin ;
385
- pfout = conn -> Pfout ;
386
- pfdebug = conn -> Pfdebug ;
387
-
388
539
/*clear the error string */
389
540
conn -> errorMessage [0 ] = '\0' ;
390
541
@@ -406,129 +557,20 @@ PQexec(PGconn* conn, const char* query)
406
557
sprintf (buffer ,"Q%s" ,query );
407
558
408
559
/* send the query to the backend; */
409
- if (pqPuts (buffer ,pfout , pfdebug ) == 1 ) {
560
+ if (pqPuts (buffer , conn -> Pfout , conn -> Pfdebug ) == 1 ) {
410
561
(void ) sprintf (conn -> errorMessage ,
411
562
"PQexec() -- while sending query: %s\n"
412
563
"-- fprintf to Pfout failed: errno=%d\n%s\n" ,
413
- query , errno ,strerror (errno ));
564
+ query , errno , strerror (errno ));
414
565
return NULL ;
415
566
}
416
567
417
- /* loop forever because multiple messages, especially NOTICES,
418
- can come back from the backend
419
- NOTICES are output directly to stderr
420
- */
421
-
422
- while (1 ) {
568
+ process_response_from_backend (conn -> Pfin , conn -> Pfout , conn -> Pfdebug , conn ,
569
+ & result , conn -> errorMessage );
570
+ return (result );
571
+ }
423
572
424
- /* read the result id */
425
- id = pqGetc (pfin ,pfdebug );
426
- if (id == EOF ) {
427
- /* hmm, no response from the backend-end, that's bad */
428
- (void ) sprintf (conn -> errorMessage ,
429
- "PQexec() -- Request was sent to backend, but backend "
430
- "closed the channel before "
431
- "responding. This probably means the backend "
432
- "terminated abnormally before or while processing "
433
- "the request.\n" );
434
- conn -> status = CONNECTION_BAD ; /* No more connection to backend */
435
- return (PGresult * )NULL ;
436
- }
437
573
438
- switch (id ) {
439
- case 'A' :
440
- newNotify = (PGnotify * )malloc (sizeof (PGnotify ));
441
- pqGetInt (& (newNotify -> be_pid ), 4 , pfin , pfdebug );
442
- pqGets (newNotify -> relname , NAMEDATALEN , pfin , pfdebug );
443
- DLAddTail (conn -> notifyList , DLNewElem (newNotify ));
444
- /* async messages are piggy'ed back on other messages,
445
- so we stay in the while loop for other messages */
446
- break ;
447
- case 'C' : /* portal query command, no rows returned */
448
- if (pqGets (cmdStatus , MAX_MESSAGE_LEN , pfin , pfdebug ) == 1 ) {
449
- sprintf (conn -> errorMessage ,
450
- "PQexec() -- query command completed, "
451
- "but return message from backend cannot be read." );
452
- return (PGresult * )NULL ;
453
- }
454
- else {
455
- /*
456
- // since backend may produce more than one result for some commands
457
- // need to poll until clear
458
- // send an empty query down, and keep reading out of the pipe
459
- // until an 'I' is received.
460
- */
461
- pqPuts ("Q" ,pfout ,pfdebug ); /* send an empty query */
462
- /*
463
- * Increment a flag and process messages in the usual way because
464
- * there may be async notifications pending. DZ - 31-8-1996
465
- */
466
- emptiesPending ++ ;
467
- emptySent = true;
468
- }
469
- break ;
470
- case 'E' : /* error return */
471
- if (pqGets (conn -> errorMessage , ERROR_MSG_LENGTH , pfin , pfdebug ) == 1 ) {
472
- (void ) sprintf (conn -> errorMessage ,
473
- "PQexec() -- error return detected from backend, "
474
- "but attempt to read the error message failed." );
475
- }
476
- return (PGresult * )NULL ;
477
- break ;
478
- case 'I' : /* empty query */
479
- /* read the throw away the closing '\0' */
480
- {
481
- int c ;
482
- if ((c = pqGetc (pfin ,pfdebug )) != '\0' ) {
483
- fprintf (stderr ,"error!, unexpected character %c following 'I'\n" , c );
484
- }
485
- if (emptiesPending ) {
486
- if (-- emptiesPending == 0 && emptySent ) { /* is this the last one? */
487
- /*
488
- * If this is the result of a portal query command set the
489
- * command status and message accordingly. DZ - 31-8-1996
490
- */
491
- result = makeEmptyPGresult (conn ,PGRES_COMMAND_OK );
492
- strncpy (result -> cmdStatus ,cmdStatus , CMDSTATUS_LEN - 1 );
493
- return result ;
494
- }
495
- }
496
- else {
497
- result = makeEmptyPGresult (conn , PGRES_EMPTY_QUERY );
498
- return result ;
499
- }
500
- }
501
- break ;
502
- case 'N' : /* notices from the backend */
503
- if (pqGets (conn -> errorMessage , ERROR_MSG_LENGTH , pfin , pfdebug ) == 1 ) {
504
- sprintf (conn -> errorMessage ,
505
- "PQexec() -- Notice detected from backend, "
506
- "but attempt to read the notice failed." );
507
- return (PGresult * )NULL ;
508
- }
509
- else
510
- fprintf (stderr ,"%s" , conn -> errorMessage );
511
- break ;
512
- case 'P' : /* synchronous (normal) portal */
513
- pqGets (pname ,MAX_MESSAGE_LEN ,pfin , pfdebug ); /* read in portal name*/
514
- break ;
515
- case 'T' : /* actual row results: */
516
- return makePGresult (conn , pname );
517
- break ;
518
- case 'D' : /* copy command began successfully */
519
- return makeEmptyPGresult (conn ,PGRES_COPY_IN );
520
- break ;
521
- case 'B' : /* copy command began successfully */
522
- return makeEmptyPGresult (conn ,PGRES_COPY_OUT );
523
- break ;
524
- default :
525
- sprintf (conn -> errorMessage ,
526
- "unknown protocol character %c read from backend\n" ,
527
- id );
528
- return (PGresult * )NULL ;
529
- } /* switch */
530
- } /* while (1)*/
531
- }
532
574
533
575
/*
534
576
* PQnotifies
0 commit comments