Skip site navigation (1) Skip section navigation (2)

Re: libpq++

From: Justin Banks <justinb(at)mr-boo(dot)com>
To: Bruce Momjian <pgman(at)candle(dot)pha(dot)pa(dot)us>
Cc: justinb(at)tricord(dot)com, PostgreSQL-interfaces <pgsql-interfaces(at)postgresql(dot)org>
Subject: Re: libpq++
Date: 2001-04-30 03:07:10
Message-ID: 15084.54539.44529.709222@dervish.mr-boo.com (view raw or flat)
Thread:
Lists: pgsql-interfaces
>>>>> "Bruce" == Bruce Momjian <pgman(at)candle(dot)pha(dot)pa(dot)us> writes:

  Bruce> I am not so much the libpq++ maintainer as the one who applies
  Bruce> people's patches.  There is an interfaces list that would love to
  Bruce> hear about your work.  I am CC'ing them on this.  We certainly need
  Bruce> libpq++ improvements.  If you would prefer not to deal with the
  Bruce> interfaces list, send something to me and I will send it over there.

Here's what I've done. The following code will create a number of different
connections to the B.E., even though there's no reason to have more than
one. This prevents one from inheriting PgDatabase, and then creating an array
of 100 or so of those objects.

#include <iostream.h>
#include <stdlib.h>
#include <libpq++.h>


class base : public PgDatabase {
  public:
    base() {
      cout << "base class instantiating" << endl;
      Connect("host=db dbname=golem user=golemadmin password=bleen");
    }
    virtual ~base() {
      cout << "Base class destructing" << endl;
    }

};

class derived : public base {
  public:
    derived() {
      cout << "derived class instantiating" << endl;
    }
    ~derived() {
      cout << "derived class destructing" << endl;
    }
};

int 
main(int argc, char* argv[]) {
  int cnt, tuples;
  derived* classes, *ptr;
  derived single;

  if(argc > 1)
    cnt = atoi(argv[1]);
  else
    cnt = 5;

  cout << "getting array of " << cnt << " objects" << endl;
  classes = new derived[cnt];

  cout << "array allocated, sleeping for validation" << endl;
  sleep(5);
  for(int i = 0; i < cnt; i++) {
    cout << "testing object " << i << endl;
    ptr = &(classes[i]);
    ptr->Exec("select * from defaults");
    tuples = ptr->Tuples();
    cout << "got " << tuples << " tuples" << endl;
    for(int j = 0; j < tuples; j++) {
      cout << "4th field is " << ptr->GetValue(j, 4) << endl;
    }
  }
  delete[] classes;

  cout << "aggregates deleted" << endl;
  single.Exec("select table_name from tables limit 1");
  cout << "exec of single finished" << endl;
  cout << "value is " << single.GetValue(0, 0) << endl;
  exit(0);
}


What I'd like to have happen is for a total of one connection to the database
to be made, and have all these objects share that connection transparently. I
made this happen by using a shared memory segment to store the connection
pointer. Here's the diff. It doesn't seem to break anything, but then again,
my coverage is rather limited at this point.

Diff follows :

--- pgconnection.cc.orig	Sun Apr 29 16:09:02 2001
+++ pgconnection.cc	Sun Apr 29 21:35:36 2001
@@ -17,7 +17,6 @@
 
 #include "pgconnection.h"
 
-
 // ****************************************************************
 //
 // PgConnection Implementation
@@ -54,7 +53,15 @@
 // close down the connection if there is one
 void PgConnection::CloseConnection() 
 {
-  // if the connection is open, close it first
+#if USING_SYSV_IPC == 1
+  struct shmid_ds shminfo;
+
+  shmctl(shmid, IPC_STAT, &shminfo);
+  //
+  // if we're the only one left ...
+  //
+  if(shminfo.shm_nattch == 1) {
+#endif    
   if ( pgCloseConnection ) {    
        if(pgResult) PQclear(pgResult);
        pgResult=NULL;
@@ -62,6 +69,10 @@
        pgConn=NULL;
        pgCloseConnection=0;
   }
+#if USING_SYSV_IPC == 1
+  }
+  shmdt(addr);
+#endif
 }
 
 
@@ -69,11 +80,60 @@
 // establish a connection to a backend
 ConnStatusType PgConnection::Connect(const char* conninfo)
 {
+#if USING_SYSV_IPC == 1
+  int key = (int)getpid();
+  struct shmid_ds shminfo;
+#endif
+
   // if the connection is open, close it first
   CloseConnection();
 
   // Connect to the database
+#if USING_SYSV_IPC == 1
+  if((shmid = shmget(key, sizeof(addr), IPC_CREAT|SHM_W|SHM_R)) >= 0) {
+    if((addr = (int*)shmat(shmid, 0, 0)) > 0) {
+      //
+      // now, we have our segment. If we're the first attacher, then we need
+      // to do the connect. If we're not the first attacher, then the
+      // connection is already made, we just need to check and make sure
+      // it's okay, connecting again if we have to.
+      //
+      if(shmctl(shmid, IPC_STAT, &shminfo) == 0) {
+        if(shminfo.shm_nattch == 1) {
+          pgConn = PQconnectdb(conninfo);
+          *addr = (int)pgConn;
+        }
+        else {
+          pgConn = (PGconn*)*addr;
+          if(Status() == CONNECTION_BAD) {
+            pgConn = PQconnectdb(conninfo);
+            *addr = (int)pgConn;
+          }
+        }
+      }
+      else {
+        //
+        // fallback to safe connection
+        //
+        pgConn = PQconnectdb(conninfo);
+      }
+    }
+    else {
+      //
+      // fallback to safe connection
+      //
+      pgConn = PQconnectdb(conninfo);
+    }
+  }
+  else {
+    // 
+    // fallback to safe connection
+    //
+    pgConn = PQconnectdb(conninfo);
+  }
+#else
   pgConn = PQconnectdb(conninfo);
+#endif
 
   // Now we have a connection we must close (even if it's bad!)
   pgCloseConnection = 1;
--- pgconnection.h.orig	Sun Apr 29 16:09:54 2001
+++ pgconnection.h	Sun Apr 29 17:07:57 2001
@@ -46,6 +46,15 @@
 using namespace std;
 #endif
 
+#if HAVE_SYS_SHM_H == 1 && HAVE_SYS_IPC_H == 1
+ #include <sys/types.h>
+ #include <sys/ipc.h>
+ #include <sys/shm.h>
+ #include <unistd.h>
+ #define USING_SYSV_IPC 1
+#else
+ #define USING_SYSV_IPC 0
+#endif
 
 // ****************************************************************
 //
@@ -91,6 +100,9 @@
 // so make copy constructor and assignment op private.
    PgConnection(const PgConnection&);
    PgConnection& operator= (const PgConnection&);
+#if USING_SYSV_IPC == 1
+  int shmid, *addr;
+#endif
 };
 
 #endif	// PGCONNECTION_H

I think that's it. I've got more at work, so I may have missed something, but
I don't think so.

-justinb

-- 
Justin Banks @ home
Distrust any enterprise that requires new clothes. -Thoreau


In response to

  • Re: libpq++ at 2001-04-29 20:04:49 from Bruce Momjian

pgsql-interfaces by date

Next:From: Tom LaneDate: 2001-04-30 05:52:57
Subject: Re: Re: can external C-function get multiple rows?
Previous:From: Bruce MomjianDate: 2001-04-29 20:04:49
Subject: Re: libpq++

Privacy Policy | About PostgreSQL
Copyright © 1996-2014 The PostgreSQL Global Development Group