TPostgreSQL + FWPG_* Funciones
Fuente: source/function/pgsuport.prg
FiveWin provides PostgreSQL integration via the pgsuport.prg module, which bridges
the Harbour hbpgsql library (a libpq wrapper) with FWH components such
as TXBrowse and TDataRow. Rather than requiring a compile-time link to
hbpgsql, the module uses a lazy-loading mechanism to resolve libpq
function pointers at runtime, making the library dependency optional.
PGLinked() - Lazy-Loading Function Resolution
The internal static function PGLinked() is called automatically on the first invocation
of any FWPG_ function. It uses HB_FUNCPTR() to locate the Harbour-level
libpq wrappers provided by the hbpgsql library. If PQEXEC
is found, pointers are cached for the following operations:
| Pointer Variable | hbpgsql Function | Purpose |
|---|---|---|
pPQExec | PQEXEC | Synchronous command execution |
pPQExecParams | PQEXECPARAMS | Parameterized command execution |
pPQMetaData | PQMETADATA | Result set schema retrieval |
pPQGetValue | PQGETVALUE | Data retrieval for specific row/column |
pPQResultStatus | PQRESULTSTATUS | Status check (Success / Tuples / Error) |
pPQlastrec | PQLASTREC | Row count retrieval |
pPQFCount | PQFCOUNT | Column count retrieval |
pPQcmdTuples | PQCMDTUPLES | Affected rows for DML |
pPQresultErrorMessage | PQRESULTERRORMESSAGE | Detailed server error text |
These resolved function pointers are invoked via the HB_ExecFromArray() mechanism
through #xtranslate macros (PQ_Exec, PQ_ExecParams,
PQ_MetaData, etc.).
FWPG_Execute() - Query Execution
The central function for all PostgreSQL interaction is FWPG_Execute:
Signature:
FWPG_Execute( pDB, cSql, aParams ) && -> aResult | nAffected | .F.
Parameters:
pDB- The database connection object (or its:pDBhandle).cSql- The SQL statement to execute.aParams- Optional array of parameter values for parameterized queries.
Return values:
- For
SELECTqueries (PGRES_TUPLES_OK): Returns a 2D array (rows x columns) of Harbour-typed values. - For DML commands (
PGRES_COMMAND_OK): Returns the numeric count of affected rows. - On error: Sets the error state on the connection object and returns
.F..
When parameters are supplied via aParams, each value is converted to an SQL-safe string
using FW_ValToSQL(u, , "PG") and the query is executed via PQ_ExecParams,
preventing SQL injection.
PostgreSQL-to-Harbour Type Mapping
Query results arrive from libpq as strings. The internal GetFieldTypes()
function inspects column metadata for specific keywords to determine the optimal Harbour type:
| Column Keyword | Harbour Type | Description |
|---|---|---|
bool | L | Logical (converted from 't'/'f') |
date | D | Date |
timestamp | T | Timestamp (date+time) |
bytea | m | Binary memo (lowercase m) |
text | M | Character memo (uppercase M) |
int, numeric, decimal | N | Numeric |
serial | N | Auto-increment numeric |
float, double, real | N | Floating-point numeric |
money | N | Currency numeric |
| Default | C | Character string |
Metadata and Structure Funciones
FWPG_MetaStruct()
FWPG_MetaStruct( res ) && -> aStruct
Returns an array of column metadata for a query result. Each element is an array indexed by the following constants:
| Index | Constant | Value | Description |
|---|---|---|---|
| 1 | _STRU_FIELDNAME | 1 | Field (column) name |
| 2 | _STRU_FIELDTYPE | 2 | Harbour type code |
| 3 | _STRU_FIELDLEN | 3 | Field length |
| 4 | _STRU_FIELDDEC | 4 | Decimal places |
| 5 | _STRU_TABLE | 5 | Table OID |
| 6 | _STRU_TABLECOL | 6 | Column ordinal within table |
| 7 | _STRU_TABLENAME | 7 | Source table name |
| 8 | _STRU_COLNAME | 8 | Column name in source table |
| 9 | _STRU_DEFAULT | 9 | Default value expression |
| 10 | _STRU_PRI | 10 | Primary key indicator ("PRI" if key) |
FWPG_Structure()
FWPG_Structure( oQry ) && -> aStruct
Returns an enhanced structure array for a PostgreSQL query object. Enriches the base
aStruct with table name, column name, and primary key information by querying
information_schema.columns. Adjusts field types for bytea (mapped to
"m"), timestamp (mapped to "T"), and auto-increment columns
(mapped to "+").
FWPG_FieldGet()
FWPG_FieldGet( oQry, nFldNo ) && -> uVal
A specialized field getter that handles PostgreSQL-specific formatting:
- Converts
\xhex prefixes (frombyteacolumns) to binary strings. - Processes
timestampvalues withFW_STR2DT(). - Applies Unicode padding via
FW_UTF8PADCHAR()when Unicode mode is active. - Accepts field names (character) in addition to numeric field positions.
- Falls back to evaluating expression blocks for computed columns.
FWPG_Skipper()
FWPG_Skipper( oQry, nSkip ) && -> nSkipped
Navigation helper used by TXBrowse codeblocks for record skipping. Calculates
the new record offset relative to the current position, clamping to valid range
[1, nLastRec]. Returns the actual number of records skipped.
Utility Funciones
| Function | Description |
|---|---|
FWPG_ListDbs( oServer ) | Returns an array of database names on the server (querying pg_database). |
FWPG_CurrentDB( oServer ) | Returns the name of the current database via current_database(). |
FWPG_ListSchemas( oServer ) | Returns an array of schema names from information_schema.schemata. |
FWPG_ImportFromDBF( oCn, cDbf, cTable, lcAutoInc ) | Imports a DBF file into a PostgreSQL table. Creates the table structure, auto-maps memo types (binary → bytea, text → TEXT), and bulk-inserts via batching (100 rows by default). |
FWPG_CreateTableSQL( cTable, aStruct, lcAutoInc ) | Generates a CREATE TABLE SQL statement from a DBF-like structure array using SERIAL PRIMARY KEY for auto-increment columns. |
FWPG_TableNameFromID( oQry, oID ) | Resolves a PostgreSQL table OID to a table name via pg_class. |
FWPG_PrimaryKeys( oQry, cTable ) | Returns an array of primary key columns for a given table from information_schema.key_column_usage. |
TXBrowse Integration
TXBrowse consumes PostgreSQL data sets through standard codeblock interfaces.
The FWPG_Skipper function provides the bSkip codeblock; the query
object's bGoTop, bGoBottom, bEof, bBof,
and bBookMark codeblocks are set directly on the query object. Direct in-cell
editing is supported via FWPG_XBrSaveData( oCol, xValue ), which constructs
and executes UPDATE SQL targeting the source table's primary key.
TDataRow Integration
TDataRow provides native PostgreSQL support through two internal methods:
- ReadPQQ: Reads field values and metadata from a PostgreSQL query object into
the
TDataRowedit buffer (aData/aOrg). - SavePQQ: Generates and executes the necessary SQL
UPDATEorINSERTstatements viaFWPG_Executeto persist changes made through the data row interface.
Example: Connect, Query, and Browse
#include "FiveWin.ch"
function Main()
local oServer, oQry, oWnd, oBrw, aDbs
// Open a PostgreSQL connection using hbpgsql
oServer := TPostgreSQL():New( "localhost", "mydb", "postgres", "password", 5432 )
if oServer:lError
MsgStop( "Connection failed: " + oServer:cError )
return nil
endif
// List available databases
aDbs := FWPG_ListDbs( oServer )
XBROWSER aDbs TITLE "Databases on Server"
// Execute a query
oQry := TPostgreSQLQuery():New( oServer, "SELECT id, name, email, city FROM customers ORDER BY name" )
if oQry:nLastRec > 0
DEFINE WINDOW oWnd TITLE "Customers"
@ 0, 0 XBROWSE oBrw OF oWnd ;
COLUMNS "id", "name", "email", "city" ;
COLSIZES 50, 200, 250, 150
oBrw:nMarqueeStyle := 3
oBrw:lCanPaste := .t.
// Connect XBrowse to PostgreSQL query via codeblocks
oBrw:bSkip := { |nSkip| FWPG_Skipper( oQry, nSkip ) }
oBrw:bGoTop := { || oQry:GoTop() }
oBrw:bGoBottom := { || oQry:GoBottom() }
oBrw:bEof := { || oQry:RecNo() > oQry:nLastRec }
oBrw:bBof := { || oQry:RecNo() == 0 }
oBrw:bBookMark := { || oQry:RecNo() }
oBrw:bStrData := { |n| FWPG_FieldGet( oQry, n ) }
oBrw:bKeyNo := { || oQry:RecNo() }
oBrw:CreateFromCode()
ACTIVATE WINDOW oWnd MAXIMIZED
else
MsgInfo( "No records found" )
endif
oQry:End()
oServer:End()
return nil
Notes
- PostgreSQL support requires the Harbour
hbpgsqllibrary to be linked into your application. ThePGLinked()function resolves the library's function pointers at runtime; ifhbpgsqlis not linked, allFWPG_Funciones return.F.gracefully. - Parameterized queries via
aParamsare strongly recommended for dynamic SQL to prevent injection attacks. Values are escaped usingFW_ValToSQL( u, , "PG" ). - The
TDataRowintegration (ReadPQQ/SavePQQ) enables record-at-a-time editing with automatic change tracking and SQL generation. - In-cell editing via XBrowse (
FWPG_XBrSaveData) requires that the query's source table has a primary key defined and thatFWPG_Structure()has been called to populate the structure metadata. - The
FWPG_Structure()function automatically queriesinformation_schema.columnsto resolve table and column names from OID references, providing full metadata for complex JOIN queries.