ODBC Driver for PostGreSQL

Xbase++ 2.0 Build 554 or later
Message
Author
User avatar
rdonnay
Site Admin
Posts: 4722
Joined: Wed Jan 27, 2010 6:58 pm
Location: Boise, Idaho USA
Contact:

Re: ODBC Driver for PostGreSQL

#11 Post by rdonnay »

Here is a test program I wrote to compare performance of the PGDBE to the ODBCDBE.

Passing a 1 uses the ODBCDBE
Passing a 2 uses the PGDBE

The ODBCDBE out-performs the PGDBE by about 40% on the average.
These tests are based on SQL SELECT statements, not ISAM.

This example retrieves data from SENDMAIL.DBF which has 271,454 records.
The cursor is returned in .64 seconds (ODBCDBE) or 1.03 seconds (PGDBE).
The output to the "output pane" for the same statement using pgAdmin III is about 1.18 seconds.

Code: Select all

#INCLUDE "dcdialog.ch"
#include "pgdbe.ch"
#INCLUDE "odbcdbe.CH"
#INCLUDE "sqlcmd.CH"

// Execute a statement (ODBCDBE)
#xcommand PGSQL <(x)> [VIA <session>] [TO <y>] ;
              => [<y> :=] PG_SqlStmtExec(<(x)>,<session>)

FUNCTION Main( cDbe )

LOCAL cConnect, oSession, i, oBrowse, aStru, GetList[0], GetOptions, ;
      cSQL1, cSQL2, lStatus, nDbe, cAlias, oStmt, nSeconds, nTime

DEFAULT cDbe := '1'

nDbe := Val(cDbe)

IF nDbe == 2

  IF(!DbeLoad("pgdbe"))
    DCMSGBOX "Unable to load the PostgreSQL DatabaseEngine"
    QUIT
  ENDIF

  cConnect := "DBE=pgdbe;SERVER=localhost;DB=medallion;UID=postgres;PWD=" + GetEnv('POSTGRESQL_PASSWORD')

ELSEIF nDbe == 1

  IF(!DbeLoad("odbcdbe"))
    DCMSGBOX "Unable to load the ODBC DatabaseEngine"
    QUIT
  ENDIF

  cConnect := "DBE=odbcdbe;DRIVER={PostgreSQL Unicode};"
  cConnect += "SERVER=localhost;PORT=5432;Database=medallion;UID=postgres;PWD=" + GetEnv('POSTGRESQL_PASSWORD')

ENDIF

SET NULLVALUE OFF
dbSetNullValue(.f.)

oSession := DacSession():New( cConnect )

IF .NOT. oSession:isConnected()
  DCMSGBOX oSession:GetLastMessage(), ;
           "Unable to establish connection to server"
  QUIT
ENDIF

TEXT INTO cSQL1 WRAP
SELECT date, time, subject, mail_to, __record from sendmail
       where error_code >= 0
       order by ? ;
ENDTEXT

cSQL2 := DC_ApplySQLParams( cSQL1, {'[__record]'} )

nSeconds := Seconds()

IF nDbe == 1

  PGSQL (cSQL2) VIA (oSession) TO lStatus
  IF !lStatus
    RETURN .f.
  ENDIF

ELSE

  oStmt := DacSqlStatement():fromChar(cSQL2)
  oStmt:build():query()

ENDIF

nTime := Seconds() - nSeconds

cAlias := Alias()

wtf reccount(), cAlias

@ 0,0 DCBROWSE oBrowse ALIAS cAlias SIZE 120,25 ;
      RESIZE DCGUI_RESIZE_RESIZEONLY

aStru := (cAlias)->(dbStruct())

FOR i := 1 TO Len(aStru)
  DCBROWSECOL DATA FieldWBlock(aStru[i,1],cAlias) ;
    HEADER DC_CapFirst(aStru[i,1]) WIDTH Min(aStru[i,3],10) PARENT oBrowse ;
    SORT SortBlock(aStru[i,1],oSession,@oBrowse,cAlias,nDbe,cSQL1) ;
    PICTURE IIF( aStru[i,1] == '__record','9999999',nil)
NEXT

DCGETOPTIONS RESIZE
DCREAD GUI FIT ;
   TITLE 'PostGreSQL test (' + IIF(nDbe==1,'ODBCDBE','PGDBE') + ;
          ') (' + Alltrim(Str(nTime)) + ')';
   OPTIONS GetOptions

// Disconnect from server
oSession:disconnect()

RETURN nil

* -----------

PROCEDURE Appsys ; RETURN

* -----------

STATIC FUNCTION SortBlock( cFieldName, oSession, oBrowse, cAlias, nDbe, cSQL )

RETURN {||Resort(cFieldName,oSession,oBrowse,cAlias,nDbe,cSQL)}

* -----------

STATIC FUNCTION ReSort( cFieldName, oSession, oBrowse, cAlias, nDbe, cSQL )

LOCAL oStmt, lStatus, nSeconds

(cAlias)->(dbCloseArea())

cSQL := Strtran(cSQL,'?',cFieldName)

nSeconds := Seconds()

IF nDbe == 2

  oStmt := DacSqlStatement():fromChar(cSQL)
  oStmt:build():query()

ELSE

  PGSQL (cSQL) VIA (oSession) TO lStatus

ENDIF

wtf Seconds() - nSeconds

oBrowse:refreshAll()

RETURN nil

* ---------

FUNCTION PG_SqlStmtExec(cSql,oSession)

LOCAL oError, lStatus := .f., GetList[0], GetOptions, ;
      bError := ErrorBlock({|oError|break(oError)}), ;
      aStack[0], aStackList[0], i := 1, cSqlError

BEGIN SEQUENCE

  // Execute a statement
  lStatus := SqlStmtExec(cSql,oSession,,,.F.)

RECOVER USING oError

  DO WHILE .t.

    AAdd( aStackList, "Called from " + Trim(ProcName(i)) + ;
       "(" + Alltrim(Str(ProcLine(i))) + ")" )
    i++
    IF Empty(ProcName(i))
      EXIT
    ENDIF

  ENDDO

  cSqlError := OdbcDebug(oSession)[15,2]

  @ 0,0 DCSAY 'Error in SQL statement:' SAYSIZE 0 FONT '10.Lucida Console' ;
        RESIZE DCGUI_RESIZE_REPOSONLY_Y

  @ 1,0 DCMULTILINE cSql SIZE 120,18 FONT '10.Lucida Console' NOHSCROLL ;
        RESIZE DCGUI_RESIZE_RESIZEONLY

  @ 20,0 DCMULTILINE cSqlError SIZE 120,3 FONT '8.Lucida Console' NOHSCROLL ;
        RESIZE DCGUI_RESIZE_REPOSY_RESIZEX

  FOR i := 1 TO Len(aStackList)
    @ 23+i,0 DCSAY aStackList[i] FONT '10.Lucida Console' SAYSIZE 0 ;
      RESIZE DCGUI_RESIZE_REPOSONLY_Y
  NEXT

  DCGETOPTIONS RESIZE

  DCREAD GUI FIT TITLE 'SQL Error' BUTTONS DCGUI_BUTTON_OK ;
     MODAL OPTIONS GetOptions

END SEQUENCE

ErrorBlock(bError)

RETURN lStatus
The eXpress train is coming - and it has more cars.

User avatar
Auge_Ohr
Posts: 1405
Joined: Wed Feb 24, 2010 3:44 pm

Re: ODBC Driver for PostGreSQL

#12 Post by Auge_Ohr »

rdonnay wrote: The cursor is returned in .64 seconds (ODBCDBE) or 1.03 seconds (PGDBE).
The output to the "output pane" for the same statement using pgAdmin III is about 1.18 seconds.
i wonder that PgAdmin3 is slower than PgDBE :o
would be interesting how fast native Solution is ... :whistle:

:think: ... hm ... how to create a "big" Reference DBF so we can testdrive with same data ...
greetings by OHR
Jimmy

User avatar
rdonnay
Site Admin
Posts: 4722
Joined: Wed Jan 27, 2010 6:58 pm
Location: Boise, Idaho USA
Contact:

Re: ODBC Driver for PostGreSQL

#13 Post by rdonnay »

i wonder that PgAdmin3 is slower than PgDBE :o
There was probably additional time required to create the browse view.
That was not considered in my tests of ODBCDBE and PGDBE.
I only record the time to create the cursor.
It also takes additional time to create the browse view in Xbase++.
The eXpress train is coming - and it has more cars.

Post Reply