From 5fffa30386502b5423e45c2ed5e6af756b11c7b4 Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Tue, 28 May 2024 10:17:01 +0900 Subject: Rename nt* sql related files to equivalent tq* Signed-off-by: Michele Calgaro --- src/sql/drivers/psql/qsql_psql.cpp | 1142 ----------------------------------- src/sql/drivers/psql/qsql_psql.h | 132 ---- src/sql/drivers/psql/tqsql_psql.cpp | 1142 +++++++++++++++++++++++++++++++++++ src/sql/drivers/psql/tqsql_psql.h | 132 ++++ 4 files changed, 1274 insertions(+), 1274 deletions(-) delete mode 100644 src/sql/drivers/psql/qsql_psql.cpp delete mode 100644 src/sql/drivers/psql/qsql_psql.h create mode 100644 src/sql/drivers/psql/tqsql_psql.cpp create mode 100644 src/sql/drivers/psql/tqsql_psql.h (limited to 'src/sql/drivers/psql') diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp deleted file mode 100644 index 7a12fe8c6..000000000 --- a/src/sql/drivers/psql/qsql_psql.cpp +++ /dev/null @@ -1,1142 +0,0 @@ -/**************************************************************************** -** -** Implementation of PostgreSQL driver classes -** -** Created : 001103 -** -** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. -** -** This file is part of the sql module of the TQt GUI Toolkit. -** -** This file may be used under the terms of the GNU General -** Public License versions 2.0 or 3.0 as published by the Free -** Software Foundation and appearing in the files LICENSE.GPL2 -** and LICENSE.GPL3 included in the packaging of this file. -** Alternatively you may (at your option) use any later version -** of the GNU General Public License if such license has been -** publicly approved by Trolltech ASA (or its successors, if any) -** and the KDE Free TQt Foundation. -** -** Please review the following information to ensure GNU General -** Public Licensing requirements will be met: -** http://trolltech.com/products/qt/licenses/licensing/opensource/. -** If you are unsure which license is appropriate for your use, please -** review the following information: -** http://trolltech.com/products/qt/licenses/licensing/licensingoverview -** or contact the sales department at sales@trolltech.com. -** -** This file may be used under the terms of the Q Public License as -** defined by Trolltech ASA and appearing in the file LICENSE.TQPL -** included in the packaging of this file. Licensees holding valid TQt -** Commercial licenses may use this file in accordance with the TQt -** Commercial License Agreement provided with the Software. -** -** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, -** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted -** herein. -** -**********************************************************************/ - -#include "qsql_psql.h" -#include - -#include - -#include -#include -#include -#include -// PostgreSQL header included by redefines DEBUG. -#if defined(DEBUG) -# undef DEBUG -#endif -#include -#include -// PostgreSQL header redefines errno erroneously. -#if defined(errno) -# undef errno -#endif -#define errno qt_psql_errno -#include -#undef errno -#ifdef open -# undef open -#endif - -TQPtrDict *tqSqlDriverExtDict(); -TQPtrDict *tqSqlOpenExtDict(); - -class TQPSQLPrivate -{ -public: - TQPSQLPrivate():connection(0), result(0), isUtf8(FALSE) {} - PGconn *connection; - PGresult *result; - bool isUtf8; -}; - -class TQPSQLDriverExtension : public TQSqlDriverExtension -{ -public: - TQPSQLDriverExtension( TQPSQLDriver *dri ) - : TQSqlDriverExtension(), driver(dri) { } - ~TQPSQLDriverExtension() {} - - bool isOpen() const; -private: - TQPSQLDriver *driver; -}; - -bool TQPSQLDriverExtension::isOpen() const -{ - return PQstatus( driver->connection() ) == CONNECTION_OK; -} - -class TQPSQLOpenExtension : public TQSqlOpenExtension -{ -public: - TQPSQLOpenExtension( TQPSQLDriver *dri ) - : TQSqlOpenExtension(), driver(dri) { } - ~TQPSQLOpenExtension() {} - - bool open( const TQString& db, - const TQString& user, - const TQString& password, - const TQString& host, - int port, - const TQString& connOpts ); -private: - TQPSQLDriver *driver; -}; - -bool TQPSQLOpenExtension::open( const TQString& db, - const TQString& user, - const TQString& password, - const TQString& host, - int port, - const TQString& connOpts ) -{ - return driver->open( db, user, password, host, port, connOpts ); -} - -static TQSqlError qMakeError( const TQString& err, int type, const TQPSQLPrivate* p ) -{ - const char *s = PQerrorMessage(p->connection); - TQString msg = p->isUtf8 ? TQString::fromUtf8(s) : TQString::fromLocal8Bit(s); - return TQSqlError("TQPSQL: " + err, msg, type); -} - -static TQVariant::Type qDecodePSQLType( int t ) -{ - TQVariant::Type type = TQVariant::Invalid; - switch ( t ) { - case BOOLOID : - type = TQVariant::Bool; - break; - case INT8OID : - type = TQVariant::LongLong; - break; - case INT2OID : - // case INT2VECTOROID : // 7.x - case INT4OID : - type = TQVariant::Int; - break; - case NUMERICOID : - case FLOAT4OID : - case FLOAT8OID : - type = TQVariant::Double; - break; -#ifdef ABSTIMEOID // PostgreSQL << 12.x - case ABSTIMEOID : - case RELTIMEOID : -#endif - case DATEOID : - type = TQVariant::Date; - break; - case TIMEOID : -#ifdef TIMETZOID // 7.x - case TIMETZOID : -#endif - type = TQVariant::Time; - break; - case TIMESTAMPOID : -#ifdef DATETIMEOID - // Postgres 6.x datetime workaround. - // DATETIMEOID == TIMESTAMPOID (only the names have changed) - case DATETIMEOID : -#endif -#ifdef TIMESTAMPTZOID - // Postgres 7.2 workaround - // TIMESTAMPTZOID == TIMESTAMPOID == DATETIMEOID - case TIMESTAMPTZOID : -#endif - type = TQVariant::DateTime; - break; - // case ZPBITOID : // 7.x - // case VARBITOID : // 7.x - case OIDOID : - case BYTEAOID : - type = TQVariant::ByteArray; - break; - case REGPROCOID : - case TIDOID : - case XIDOID : - case CIDOID : - // case OIDVECTOROID : // 7.x - case UNKNOWNOID : - // case TINTERVALOID : // 7.x - type = TQVariant::Invalid; - break; - default: - case CHAROID : - case BPCHAROID : - // case LZTEXTOID : // 7.x - case VARCHAROID : - case TEXTOID : - case NAMEOID : - case CASHOID : - case INETOID : - case CIDROID : - case CIRCLEOID : - type = TQVariant::String; - break; - } - return type; -} - -TQPSQLResult::TQPSQLResult( const TQPSQLDriver* db, const TQPSQLPrivate* p ) -: TQSqlResult( db ), - currentSize( 0 ) -{ - d = new TQPSQLPrivate(); - (*d) = (*p); -} - -TQPSQLResult::~TQPSQLResult() -{ - cleanup(); - delete d; -} - -PGresult* TQPSQLResult::result() -{ - return d->result; -} - -void TQPSQLResult::cleanup() -{ - if ( d->result ) - PQclear( d->result ); - d->result = 0; - setAt( -1 ); - currentSize = 0; - setActive( FALSE ); -} - -bool TQPSQLResult::fetch( int i ) -{ - if ( !isActive() ) - return FALSE; - if ( i < 0 ) - return FALSE; - if ( i >= currentSize ) - return FALSE; - if ( at() == i ) - return TRUE; - setAt( i ); - return TRUE; -} - -bool TQPSQLResult::fetchFirst() -{ - return fetch( 0 ); -} - -bool TQPSQLResult::fetchLast() -{ - return fetch( PQntuples( d->result ) - 1 ); -} - -// some Postgres conversions -static TQPoint pointFromString( const TQString& s) -{ - // format '(x,y)' - int pivot = s.find( ',' ); - if ( pivot != -1 ) { - int x = s.mid( 1, pivot-1 ).toInt(); - int y = s.mid( pivot+1, s.length()-pivot-2 ).toInt(); - return TQPoint( x, y ) ; - } else - return TQPoint(); -} - -TQVariant TQPSQLResult::data( int i ) -{ - if ( i >= PQnfields( d->result ) ) { - tqWarning( "TQPSQLResult::data: column %d out of range", i ); - return TQVariant(); - } - int ptype = PQftype( d->result, i ); - TQVariant::Type type = qDecodePSQLType( ptype ); - const TQString val = ( d->isUtf8 && ptype != BYTEAOID ) ? - TQString::fromUtf8( PQgetvalue( d->result, at(), i ) ) : - TQString::fromLocal8Bit( PQgetvalue( d->result, at(), i ) ); - if ( PQgetisnull( d->result, at(), i ) ) { - TQVariant v; - v.cast( type ); - return v; - } - switch ( type ) { - case TQVariant::Bool: - { - TQVariant b ( (bool)(val == "t") ); - return ( b ); - } - case TQVariant::String: - return TQVariant( val ); - case TQVariant::LongLong: - if ( val[0] == '-' ) - return TQVariant( val.toLongLong() ); - else - return TQVariant( val.toULongLong() ); - case TQVariant::Int: - return TQVariant( val.toInt() ); - case TQVariant::Double: - if ( ptype == NUMERICOID ) - return TQVariant( val ); - return TQVariant( val.toDouble() ); - case TQVariant::Date: - if ( val.isEmpty() ) { - return TQVariant( TQDate() ); - } else { - return TQVariant( TQDate::fromString( val, TQt::ISODate ) ); - } - case TQVariant::Time: - if ( val.isEmpty() ) - return TQVariant( TQTime() ); - if ( val.at( val.length() - 3 ) == '+' ) - // strip the timezone - return TQVariant( TQTime::fromString( val.left( val.length() - 3 ), TQt::ISODate ) ); - return TQVariant( TQTime::fromString( val, TQt::ISODate ) ); - case TQVariant::DateTime: { - if ( val.length() < 10 ) - return TQVariant( TQDateTime() ); - // remove the timezone - TQString dtval = val; - if ( dtval.at( dtval.length() - 3 ) == '+' ) - dtval.truncate( dtval.length() - 3 ); - // milliseconds are sometimes returned with 2 digits only - if ( dtval.at( dtval.length() - 3 ).isPunct() ) - dtval += '0'; - if ( dtval.isEmpty() ) - return TQVariant( TQDateTime() ); - else - return TQVariant( TQDateTime::fromString( dtval, TQt::ISODate ) ); - } - case TQVariant::Point: - return TQVariant( pointFromString( val ) ); - case TQVariant::Rect: // format '(x,y),(x',y')' - { - int pivot = val.find( "),(" ); - if ( pivot != -1 ) - return TQVariant( TQRect( pointFromString( val.mid(pivot+2,val.length()) ), pointFromString( val.mid(0,pivot+1) ) ) ); - return TQVariant( TQRect() ); - } - case TQVariant::PointArray: // format '((x,y),(x1,y1),...,(xn,yn))' - { - TQRegExp pointPattern("\\([0-9-]*,[0-9-]*\\)"); - int points = val.contains( pointPattern ); - TQPointArray parray( points ); - int idx = 1; - for ( int i = 0; i < points; i++ ){ - int start = val.find( pointPattern, idx ); - int end = -1; - if ( start != -1 ) { - end = val.find( ')', start+1 ); - if ( end != -1 ) { - parray.setPoint( i, pointFromString( val.mid(idx, end-idx+1) ) ); - } - else - parray.setPoint( i, TQPoint() ); - } else { - parray.setPoint( i, TQPoint() ); - break; - } - idx = end+2; - } - return TQVariant( parray ); - } - case TQVariant::ByteArray: { - if ( ptype == BYTEAOID ) { - uint i = 0; - int index = 0; - uint len = val.length(); - static const TQChar backslash( '\\' ); - TQByteArray ba( (int)len ); - while ( i < len ) { - if ( val.at( i ) == backslash ) { - if ( val.at( i + 1 ).isDigit() ) { - ba[ index++ ] = (char)(val.mid( i + 1, 3 ).toInt( 0, 8 )); - i += 4; - } else { - ba[ index++ ] = val.at( i + 1 ); - i += 2; - } - } else { - ba[ index++ ] = val.at( i++ ).unicode(); - } - } - ba.resize( index ); - return TQVariant( ba ); - } - - TQByteArray ba; - ((TQSqlDriver*)driver())->beginTransaction(); - Oid oid = val.toInt(); - int fd = lo_open( d->connection, oid, INV_READ ); -#ifdef QT_CHECK_RANGE - if ( fd < 0) { - tqWarning( "TQPSQLResult::data: unable to open large object for read" ); - ((TQSqlDriver*)driver())->commitTransaction(); - return TQVariant( ba ); - } -#endif - int size = 0; - int retval = lo_lseek( d->connection, fd, 0L, SEEK_END ); - if ( retval >= 0 ) { - size = lo_tell( d->connection, fd ); - lo_lseek( d->connection, fd, 0L, SEEK_SET ); - } - if ( size == 0 ) { - lo_close( d->connection, fd ); - ((TQSqlDriver*)driver())->commitTransaction(); - return TQVariant( ba ); - } - char * buf = new char[ size ]; - -#ifdef Q_OS_WIN32 - // ### For some reason lo_read() fails if we try to read more than - // ### 32760 bytes - char * p = buf; - int nread = 0; - - while( size < nread ){ - retval = lo_read( d->connection, fd, p, 32760 ); - nread += retval; - p += retval; - } -#else - retval = lo_read( d->connection, fd, buf, size ); -#endif - - if (retval < 0) { - tqWarning( "TQPSQLResult::data: unable to read large object" ); - } else { - ba.duplicate( buf, size ); - } - delete [] buf; - lo_close( d->connection, fd ); - ((TQSqlDriver*)driver())->commitTransaction(); - return TQVariant( ba ); - } - default: - case TQVariant::Invalid: -#ifdef QT_CHECK_RANGE - tqWarning("TQPSQLResult::data: unknown data type"); -#endif - ; - } - return TQVariant(); -} - -bool TQPSQLResult::isNull( int field ) -{ - PQgetvalue( d->result, at(), field ); - return PQgetisnull( d->result, at(), field ); -} - -bool TQPSQLResult::reset ( const TQString& query ) -{ - cleanup(); - if ( !driver() ) - return FALSE; - if ( !driver()->isOpen() || driver()->isOpenError() ) - return FALSE; - setActive( FALSE ); - setAt( TQSql::BeforeFirst ); - if ( d->result ) - PQclear( d->result ); - if ( d->isUtf8 ) { - d->result = PQexec( d->connection, query.utf8().data() ); - } else { - d->result = PQexec( d->connection, query.local8Bit().data() ); - } - int status = PQresultStatus( d->result ); - if ( status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK ) { - if ( status == PGRES_TUPLES_OK ) { - setSelect( TRUE ); - currentSize = PQntuples( d->result ); - } else { - setSelect( FALSE ); - currentSize = -1; - } - setActive( TRUE ); - return TRUE; - } - setLastError( qMakeError( "Unable to create query", TQSqlError::Statement, d ) ); - return FALSE; -} - -int TQPSQLResult::size() -{ - return currentSize; -} - -int TQPSQLResult::numRowsAffected() -{ - return TQString( PQcmdTuples( d->result ) ).toInt(); -} - -/////////////////////////////////////////////////////////////////// - -static bool setEncodingUtf8( PGconn* connection ) -{ - PGresult* result = PQexec( connection, "SET CLIENT_ENCODING TO 'UNICODE'" ); - int status = PQresultStatus( result ); - PQclear( result ); - return status == PGRES_COMMAND_OK; -} - -static void setDatestyle( PGconn* connection ) -{ - PGresult* result = PQexec( connection, "SET DATESTYLE TO 'ISO'" ); -#ifdef QT_CHECK_RANGE - int status = PQresultStatus( result ); - if ( status != PGRES_COMMAND_OK ) - tqWarning( "%s", PQerrorMessage( connection ) ); -#endif - PQclear( result ); -} - -static TQPSQLDriver::Protocol getPSQLVersion( PGconn* connection ) -{ - PGresult* result = PQexec( connection, "select version()" ); - int status = PQresultStatus( result ); - if ( status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK ) { - TQString val( PQgetvalue( result, 0, 0 ) ); - PQclear( result ); - TQRegExp rx( "(\\d+)\\.(\\d+)" ); - rx.setMinimal ( TRUE ); // enforce non-greedy RegExp - if ( rx.search( val ) != -1 ) { - int vMaj = rx.cap( 1 ).toInt(); - int vMin = rx.cap( 2 ).toInt(); - if ( vMaj < 6 ) { -#ifdef QT_CHECK_RANGE - tqWarning( "This version of PostgreSQL is not supported and may not work." ); -#endif - return TQPSQLDriver::Version6; - } - if ( vMaj == 6 ) { - return TQPSQLDriver::Version6; - } else if ( vMaj == 7 ) { - if ( vMin < 1 ) - return TQPSQLDriver::Version7; - else if ( vMin < 3 ) - return TQPSQLDriver::Version71; - } - return TQPSQLDriver::Version73; - } - } else { -#ifdef QT_CHECK_RANGE - tqWarning( "This version of PostgreSQL is not supported and may not work." ); -#endif - } - - return TQPSQLDriver::Version6; -} - -TQPSQLDriver::TQPSQLDriver( TQObject * parent, const char * name ) - : TQSqlDriver(parent,name ? name : "TQPSQL"), pro( TQPSQLDriver::Version6 ) -{ - init(); -} - -TQPSQLDriver::TQPSQLDriver( PGconn * conn, TQObject * parent, const char * name ) - : TQSqlDriver(parent,name ? name : "TQPSQL"), pro( TQPSQLDriver::Version6 ) -{ - init(); - d->connection = conn; - if ( conn ) { - pro = getPSQLVersion( d->connection ); - setOpen( TRUE ); - setOpenError( FALSE ); - } -} - -void TQPSQLDriver::init() -{ - tqSqlDriverExtDict()->insert( this, new TQPSQLDriverExtension(this) ); - tqSqlOpenExtDict()->insert( this, new TQPSQLOpenExtension(this) ); - - d = new TQPSQLPrivate(); -} - -TQPSQLDriver::~TQPSQLDriver() -{ - if ( d->connection ) - PQfinish( d->connection ); - delete d; - if ( !tqSqlDriverExtDict()->isEmpty() ) { - TQSqlDriverExtension *ext = tqSqlDriverExtDict()->take( this ); - delete ext; - } - if ( !tqSqlOpenExtDict()->isEmpty() ) { - TQSqlOpenExtension *ext = tqSqlOpenExtDict()->take( this ); - delete ext; - } -} - -PGconn* TQPSQLDriver::connection() -{ - return d->connection; -} - - -bool TQPSQLDriver::hasFeature( DriverFeature f ) const -{ - switch ( f ) { - case Transactions: - return TRUE; - case QuerySize: - return TRUE; - case BLOB: - return pro >= TQPSQLDriver::Version71; - case Unicode: - return d->isUtf8; - default: - return FALSE; - } -} - -bool TQPSQLDriver::open( const TQString&, - const TQString&, - const TQString&, - const TQString&, - int ) -{ - tqWarning("TQPSQLDriver::open(): This version of open() is no longer supported." ); - return FALSE; -} - -bool TQPSQLDriver::open( const TQString & db, - const TQString & user, - const TQString & password, - const TQString & host, - int port, - const TQString& connOpts ) -{ - if ( isOpen() ) - close(); - TQString connectString; - if ( host.length() ) - connectString.append( "host=" ).append( host ); - if ( db.length() ) - connectString.append( " dbname=" ).append( db ); - if ( user.length() ) - connectString.append( " user=" ).append( user ); - if ( password.length() ) - connectString.append( " password=" ).append( password ); - if ( port > -1 ) - connectString.append( " port=" ).append( TQString::number( port ) ); - - // add any connect options - the server will handle error detection - if ( !connOpts.isEmpty() ) - connectString += " " + TQStringList::split( ';', connOpts ).join( " " ); - - d->connection = PQconnectdb( connectString.local8Bit().data() ); - if ( PQstatus( d->connection ) == CONNECTION_BAD ) { - setLastError( qMakeError("Unable to connect", TQSqlError::Connection, d ) ); - setOpenError( TRUE ); - return FALSE; - } - - pro = getPSQLVersion( d->connection ); - d->isUtf8 = setEncodingUtf8( d->connection ); - setDatestyle( d->connection ); - - setOpen( TRUE ); - setOpenError( FALSE ); - return TRUE; -} - -void TQPSQLDriver::close() -{ - if ( isOpen() ) { - if (d->connection) - PQfinish( d->connection ); - d->connection = 0; - setOpen( FALSE ); - setOpenError( FALSE ); - } -} - -bool TQPSQLDriver::ping() -{ - if ( !isOpen() ) { - return FALSE; - } - - PGresult *res = NULL; - - // Send ping - res = PQexec( d->connection, "" ); - PQclear(res); - - // Check connection status - if ( PQstatus( d->connection ) != CONNECTION_OK ) { - PQreset( d->connection ); - if ( PQstatus( d->connection ) != CONNECTION_OK ) { - setLastError( qMakeError("Unable to execute ping", TQSqlError::Statement, d ) ); - return FALSE; - } - } - return TRUE; -} - -TQSqlQuery TQPSQLDriver::createQuery() const -{ - return TQSqlQuery( new TQPSQLResult( this, d ) ); -} - -bool TQPSQLDriver::beginTransaction() -{ - if ( !isOpen() ) { -#ifdef QT_CHECK_RANGE - tqWarning( "TQPSQLDriver::beginTransaction: Database not open" ); -#endif - return FALSE; - } - PGresult* res = PQexec( d->connection, "BEGIN" ); - if ( !res || PQresultStatus( res ) != PGRES_COMMAND_OK ) { - PQclear( res ); - setLastError( qMakeError( "Could not begin transaction", TQSqlError::Transaction, d ) ); - return FALSE; - } - PQclear( res ); - return TRUE; -} - -bool TQPSQLDriver::commitTransaction() -{ - if ( !isOpen() ) { -#ifdef QT_CHECK_RANGE - tqWarning( "TQPSQLDriver::commitTransaction: Database not open" ); -#endif - return FALSE; - } - PGresult* res = PQexec( d->connection, "COMMIT" ); - if ( !res || PQresultStatus( res ) != PGRES_COMMAND_OK ) { - PQclear( res ); - setLastError( qMakeError( "Could not commit transaction", TQSqlError::Transaction, d ) ); - return FALSE; - } - PQclear( res ); - return TRUE; -} - -bool TQPSQLDriver::rollbackTransaction() -{ - if ( !isOpen() ) { -#ifdef QT_CHECK_RANGE - tqWarning( "TQPSQLDriver::rollbackTransaction: Database not open" ); -#endif - return FALSE; - } - PGresult* res = PQexec( d->connection, "ROLLBACK" ); - if ( !res || PQresultStatus( res ) != PGRES_COMMAND_OK ) { - setLastError( qMakeError( "Could not rollback transaction", TQSqlError::Transaction, d ) ); - PQclear( res ); - return FALSE; - } - PQclear( res ); - return TRUE; -} - -TQStringList TQPSQLDriver::tables( const TQString& typeName ) const -{ - TQStringList tl; - if ( !isOpen() ) - return tl; - int type = typeName.toInt(); - TQSqlQuery t = createQuery(); - t.setForwardOnly( TRUE ); - - if ( typeName.isEmpty() || ((type & (int)TQSql::Tables) == (int)TQSql::Tables) ) { - - TQString query("select relname from pg_class where (relkind = 'r') " - "and (relname !~ '^Inv') " - "and (relname !~ '^pg_') "); - if (pro >= TQPSQLDriver::Version73) - query.append("and (relnamespace not in " - "(select oid from pg_namespace where nspname = 'information_schema')) " - "and pg_table_is_visible(pg_class.oid) "); - t.exec(query); - while ( t.next() ) - tl.append( t.value(0).toString() ); - } - if ( (type & (int)TQSql::Views) == (int)TQSql::Views ) { - TQString query("select relname from pg_class where ( relkind = 'v' ) " - "and ( relname !~ '^Inv' ) " - "and ( relname !~ '^pg_' ) "); - if (pro >= TQPSQLDriver::Version73) - query.append("and (relnamespace not in " - "(select oid from pg_namespace where nspname = 'information_schema')) " - "and pg_table_is_visible(pg_class.oid) "); - t.exec(query); - while ( t.next() ) - tl.append( t.value(0).toString() ); - } - if ( (type & (int)TQSql::SystemTables) == (int)TQSql::SystemTables ) { - TQString query( "select relname from pg_class where ( relkind = 'r' ) " - "and ( relname like 'pg_%' ) " ); - if (pro >= TQPSQLDriver::Version73) - query.append( "and pg_table_is_visible(pg_class.oid) " ); - t.exec(query); - while ( t.next() ) - tl.append( t.value(0).toString() ); - } - - return tl; -} - -TQSqlIndex TQPSQLDriver::primaryIndex( const TQString& tablename ) const -{ - TQSqlIndex idx( tablename ); - if ( !isOpen() ) - return idx; - TQSqlQuery i = createQuery(); - TQString stmt; - - switch( pro ) { - case TQPSQLDriver::Version6: - stmt = "select pg_att1.attname, int(pg_att1.atttypid), pg_att2.attnum, pg_cl.relname " - "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind " - "where lower(pg_cl.relname) = '%1_pkey' "; - break; - case TQPSQLDriver::Version7: - case TQPSQLDriver::Version71: - stmt = "select pg_att1.attname, pg_att1.atttypid::int, pg_cl.relname " - "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind " - "where lower(pg_cl.relname) = '%1_pkey' "; - break; - case TQPSQLDriver::Version73: - stmt = "select pg_att1.attname, pg_att1.atttypid::int, pg_cl.relname " - "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind " - "where lower(pg_cl.relname) = '%1_pkey' " - "and pg_table_is_visible(pg_cl.oid) " - "and pg_att1.attisdropped = false "; - break; - } - stmt += "and pg_cl.oid = pg_ind.indexrelid " - "and pg_att2.attrelid = pg_ind.indexrelid " - "and pg_att1.attrelid = pg_ind.indrelid " - "and pg_att1.attnum = pg_ind.indkey[pg_att2.attnum-1] " - "order by pg_att2.attnum"; - - i.exec( stmt.arg( tablename.lower() ) ); - while ( i.isActive() && i.next() ) { - TQSqlField f( i.value(0).toString(), qDecodePSQLType( i.value(1).toInt() ) ); - idx.append( f ); - idx.setName( i.value(2).toString() ); - } - return idx; -} - -TQSqlRecord TQPSQLDriver::record( const TQString& tablename ) const -{ - TQSqlRecord fil; - if ( !isOpen() ) - return fil; - TQString stmt; - switch( pro ) { - case TQPSQLDriver::Version6: - stmt = "select pg_attribute.attname, int(pg_attribute.atttypid) " - "from pg_class, pg_attribute " - "where lower(pg_class.relname) = '%1' " - "and pg_attribute.attnum > 0 " - "and pg_attribute.attrelid = pg_class.oid "; - break; - case TQPSQLDriver::Version7: - case TQPSQLDriver::Version71: - stmt = "select pg_attribute.attname, pg_attribute.atttypid::int " - "from pg_class, pg_attribute " - "where lower(pg_class.relname) = '%1' " - "and pg_attribute.attnum > 0 " - "and pg_attribute.attrelid = pg_class.oid "; - break; - case TQPSQLDriver::Version73: - stmt = "select pg_attribute.attname, pg_attribute.atttypid::int " - "from pg_class, pg_attribute " - "where lower(pg_class.relname) = '%1' " - "and pg_table_is_visible(pg_class.oid) " - "and pg_attribute.attnum > 0 " - "and pg_attribute.attisdropped = false " - "and pg_attribute.attrelid = pg_class.oid "; - break; - } - - TQSqlQuery fi = createQuery(); - fi.exec( stmt.arg( tablename.lower() ) ); - while ( fi.next() ) { - TQSqlField f( fi.value(0).toString(), qDecodePSQLType( fi.value(1).toInt() ) ); - fil.append( f ); - } - return fil; -} - -TQSqlRecord TQPSQLDriver::record( const TQSqlQuery& query ) const -{ - TQSqlRecord fil; - if ( !isOpen() ) - return fil; - if ( query.isActive() && query.driver() == this ) { - TQPSQLResult* result = (TQPSQLResult*)query.result(); - int count = PQnfields( result->d->result ); - for ( int i = 0; i < count; ++i ) { - TQString name = PQfname( result->d->result, i ); - TQVariant::Type type = qDecodePSQLType( PQftype( result->d->result, i ) ); - TQSqlField rf( name, type ); - fil.append( rf ); - } - } - return fil; -} - -TQSqlRecordInfo TQPSQLDriver::recordInfo( const TQString& tablename ) const -{ - TQSqlRecordInfo info; - if ( !isOpen() ) - return info; - - TQString stmt; - switch( pro ) { - case TQPSQLDriver::Version6: - stmt = "select pg_attribute.attname, int(pg_attribute.atttypid), pg_attribute.attnotnull, " - "pg_attribute.attlen, pg_attribute.atttypmod, int(pg_attribute.attrelid), pg_attribute.attnum " - "from pg_class, pg_attribute " - "where lower(pg_class.relname) = '%1' " - "and pg_attribute.attnum > 0 " - "and pg_attribute.attrelid = pg_class.oid "; - break; - case TQPSQLDriver::Version7: - stmt = "select pg_attribute.attname, pg_attribute.atttypid::int, pg_attribute.attnotnull, " - "pg_attribute.attlen, pg_attribute.atttypmod, pg_attribute.attrelid::int, pg_attribute.attnum " - "from pg_class, pg_attribute " - "where lower(pg_class.relname) = '%1' " - "and pg_attribute.attnum > 0 " - "and pg_attribute.attrelid = pg_class.oid "; - break; - case TQPSQLDriver::Version71: - stmt = "select pg_attribute.attname, pg_attribute.atttypid::int, pg_attribute.attnotnull, " - "pg_attribute.attlen, pg_attribute.atttypmod, pg_attrdef.adsrc " - "from pg_class, pg_attribute " - "left join pg_attrdef on (pg_attrdef.adrelid = pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) " - "where lower(pg_class.relname) = '%1' " - "and pg_attribute.attnum > 0 " - "and pg_attribute.attrelid = pg_class.oid " - "order by pg_attribute.attnum "; - break; - case TQPSQLDriver::Version73: - stmt = "select pg_attribute.attname, pg_attribute.atttypid::int, pg_attribute.attnotnull, " - "pg_attribute.attlen, pg_attribute.atttypmod, pg_attrdef.adsrc " - "from pg_class, pg_attribute " - "left join pg_attrdef on (pg_attrdef.adrelid = pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) " - "where lower(pg_class.relname) = '%1' " - "and pg_table_is_visible(pg_class.oid) " - "and pg_attribute.attnum > 0 " - "and pg_attribute.attrelid = pg_class.oid " - "and pg_attribute.attisdropped = false " - "order by pg_attribute.attnum "; - break; - } - - TQSqlQuery query = createQuery(); - query.exec( stmt.arg( tablename.lower() ) ); - if ( pro >= TQPSQLDriver::Version71 ) { - while ( query.next() ) { - int len = query.value( 3 ).toInt(); - int precision = query.value( 4 ).toInt(); - // swap length and precision if length == -1 - if ( len == -1 && precision > -1 ) { - len = precision - 4; - precision = -1; - } - TQString defVal = query.value( 5 ).toString(); - if ( !defVal.isEmpty() && defVal.startsWith( "'" ) ) - defVal = defVal.mid( 1, defVal.length() - 2 ); - info.append( TQSqlFieldInfo( query.value( 0 ).toString(), - qDecodePSQLType( query.value( 1 ).toInt() ), - query.value( 2 ).toBool(), - len, - precision, - defVal, - query.value( 1 ).toInt() ) ); - } - } else { - // Postgres < 7.1 cannot handle outer joins - while ( query.next() ) { - TQString defVal; - TQString stmt2 = "select pg_attrdef.adsrc from pg_attrdef where " - "pg_attrdef.adrelid = %1 and pg_attrdef.adnum = %2 "; - TQSqlQuery query2 = createQuery(); - query2.exec( stmt2.arg( query.value( 5 ).toInt() ).arg( query.value( 6 ).toInt() ) ); - if ( query2.isActive() && query2.next() ) - defVal = query2.value( 0 ).toString(); - if ( !defVal.isEmpty() && defVal.startsWith( "'" ) ) - defVal = defVal.mid( 1, defVal.length() - 2 ); - int len = query.value( 3 ).toInt(); - int precision = query.value( 4 ).toInt(); - // swap length and precision if length == -1 - if ( len == -1 && precision > -1 ) { - len = precision - 4; - precision = -1; - } - info.append( TQSqlFieldInfo( query.value( 0 ).toString(), - qDecodePSQLType( query.value( 1 ).toInt() ), - query.value( 2 ).toBool(), - len, - precision, - defVal, - query.value( 1 ).toInt() ) ); - } - } - - return info; -} - -TQSqlRecordInfo TQPSQLDriver::recordInfo( const TQSqlQuery& query ) const -{ - TQSqlRecordInfo info; - if ( !isOpen() ) - return info; - if ( query.isActive() && query.driver() == this ) { - TQPSQLResult* result = (TQPSQLResult*)query.result(); - int count = PQnfields( result->d->result ); - for ( int i = 0; i < count; ++i ) { - TQString name = PQfname( result->d->result, i ); - int len = PQfsize( result->d->result, i ); - int precision = PQfmod( result->d->result, i ); - // swap length and precision if length == -1 - if ( len == -1 && precision > -1 ) { - len = precision - 4; - precision = -1; - } - info.append( TQSqlFieldInfo( name, - qDecodePSQLType( PQftype( result->d->result, i ) ), - -1, - len, - precision, - TQVariant(), - PQftype( result->d->result, i ) ) ); - } - } - return info; -} - -TQString TQPSQLDriver::formatValue( const TQSqlField* field, - bool ) const -{ - TQString r; - if ( field->isNull() ) { - r = nullText(); - } else { - switch ( field->type() ) { - case TQVariant::DateTime: - if ( field->value().toDateTime().isValid() ) { - TQDate dt = field->value().toDateTime().date(); - TQTime tm = field->value().toDateTime().time(); - // msecs need to be right aligned otherwise psql - // interpretes them wrong - r = "'" + TQString::number( dt.year() ) + "-" + - TQString::number( dt.month() ) + "-" + - TQString::number( dt.day() ) + " " + - tm.toString() + "." + - TQString::number( tm.msec() ).rightJustify( 3, '0' ) + "'"; - } else { - r = nullText(); - } - break; - case TQVariant::Time: - if ( field->value().toTime().isValid() ) { - r = field->value().toTime().toString( TQt::ISODate ); - } else { - r = nullText(); - } - case TQVariant::String: - case TQVariant::CString: { - switch ( field->value().type() ) { - case TQVariant::Rect: { - TQRect rec = field->value().toRect(); - // upper right corner then lower left according to psql docs - r = "'(" + TQString::number( rec.right() ) + - "," + TQString::number( rec.bottom() ) + - "),(" + TQString::number( rec.left() ) + - "," + TQString::number( rec.top() ) + ")'"; - break; - } - case TQVariant::Point: { - TQPoint p = field->value().toPoint(); - r = "'(" + TQString::number( p.x() ) + - "," + TQString::number( p.y() ) + ")'"; - break; - } - case TQVariant::PointArray: { - TQPointArray pa = field->value().toPointArray(); - r = "' "; - for ( int i = 0; i < (int)pa.size(); ++i ) { - r += "(" + TQString::number( pa[i].x() ) + - "," + TQString::number( pa[i].y() ) + "),"; - } - r.truncate( r.length() - 1 ); - r += "'"; - break; - } - default: - // Escape '\' characters - r = TQSqlDriver::formatValue( field ); - r.replace( "\\", "\\\\" ); - break; - } - break; - } - case TQVariant::Bool: - if ( field->value().toBool() ) - r = "TRUE"; - else - r = "FALSE"; - break; - case TQVariant::ByteArray: { - TQByteArray ba = field->value().asByteArray(); - TQString res; - r = "'"; - unsigned char uc; - for ( int i = 0; i < (int)ba.size(); ++i ) { - uc = (unsigned char) ba[ i ]; - if ( uc > 40 && uc < 92 ) { - r += uc; - } else { - r += "\\\\"; - r += TQString::number( (unsigned char) ba[ i ], 8 ).rightJustify( 3, '0', TRUE ); - } - } - r += "'"; - break; - } - default: - r = TQSqlDriver::formatValue( field ); - break; - } - } - return r; -} diff --git a/src/sql/drivers/psql/qsql_psql.h b/src/sql/drivers/psql/qsql_psql.h deleted file mode 100644 index 841ff568d..000000000 --- a/src/sql/drivers/psql/qsql_psql.h +++ /dev/null @@ -1,132 +0,0 @@ -/**************************************************************************** -** -** Definition of PostgreSQL driver classes -** -** Created : 001103 -** -** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. -** -** This file is part of the sql module of the TQt GUI Toolkit. -** -** This file may be used under the terms of the GNU General -** Public License versions 2.0 or 3.0 as published by the Free -** Software Foundation and appearing in the files LICENSE.GPL2 -** and LICENSE.GPL3 included in the packaging of this file. -** Alternatively you may (at your option) use any later version -** of the GNU General Public License if such license has been -** publicly approved by Trolltech ASA (or its successors, if any) -** and the KDE Free TQt Foundation. -** -** Please review the following information to ensure GNU General -** Public Licensing requirements will be met: -** http://trolltech.com/products/qt/licenses/licensing/opensource/. -** If you are unsure which license is appropriate for your use, please -** review the following information: -** http://trolltech.com/products/qt/licenses/licensing/licensingoverview -** or contact the sales department at sales@trolltech.com. -** -** This file may be used under the terms of the Q Public License as -** defined by Trolltech ASA and appearing in the file LICENSE.TQPL -** included in the packaging of this file. Licensees holding valid TQt -** Commercial licenses may use this file in accordance with the TQt -** Commercial License Agreement provided with the Software. -** -** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, -** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted -** herein. -** -**********************************************************************/ - -#ifndef TQSQL_PSQL_H -#define TQSQL_PSQL_H - -#include -#include -#include -#include - -#ifdef QT_PLUGIN -#define Q_EXPORT_SQLDRIVER_PSQL -#else -#define Q_EXPORT_SQLDRIVER_PSQL TQ_EXPORT -#endif - -class TQPSQLPrivate; -class TQPSQLDriver; -class TQSqlRecordInfo; - -class TQPSQLResult : public TQSqlResult -{ - friend class TQPSQLDriver; -public: - TQPSQLResult( const TQPSQLDriver* db, const TQPSQLPrivate* p ); - ~TQPSQLResult(); - PGresult* result(); -protected: - void cleanup(); - bool fetch( int i ); - bool fetchFirst(); - bool fetchLast(); - TQVariant data( int i ); - bool isNull( int field ); - bool reset ( const TQString& query ); - int size(); - int numRowsAffected(); -private: - int currentSize; - TQPSQLPrivate* d; -}; - -class Q_EXPORT_SQLDRIVER_PSQL TQPSQLDriver : public TQSqlDriver -{ -public: - enum Protocol { - Version6 = 6, - Version7 = 7, - Version71 = 8, - Version73 = 9 - }; - - TQPSQLDriver( TQObject * parent=0, const char * name=0 ); - TQPSQLDriver( PGconn * conn, TQObject * parent=0, const char * name=0 ); - ~TQPSQLDriver(); - bool hasFeature( DriverFeature f ) const; - bool open( const TQString & db, - const TQString & user = TQString::null, - const TQString & password = TQString::null, - const TQString & host = TQString::null, - int port = -1 ); - void close(); - bool ping(); - TQSqlQuery createQuery() const; - TQStringList tables( const TQString& user ) const; - TQSqlIndex primaryIndex( const TQString& tablename ) const; - TQSqlRecord record( const TQString& tablename ) const; - TQSqlRecord record( const TQSqlQuery& query ) const; - TQSqlRecordInfo recordInfo( const TQString& tablename ) const; - TQSqlRecordInfo recordInfo( const TQSqlQuery& query ) const; - - Protocol protocol() const { return pro; } - PGconn* connection(); - TQString formatValue( const TQSqlField* field, - bool trimStrings ) const; - - // ### remove me for 4.0 - bool open( const TQString& db, - const TQString& user, - const TQString& password, - const TQString& host, - int port, - const TQString& connOpts ); -protected: - bool beginTransaction(); - bool commitTransaction(); - bool rollbackTransaction(); -private: - void init(); - Protocol pro; - TQPSQLPrivate* d; -}; - -#endif diff --git a/src/sql/drivers/psql/tqsql_psql.cpp b/src/sql/drivers/psql/tqsql_psql.cpp new file mode 100644 index 000000000..1ea64fb75 --- /dev/null +++ b/src/sql/drivers/psql/tqsql_psql.cpp @@ -0,0 +1,1142 @@ +/**************************************************************************** +** +** Implementation of PostgreSQL driver classes +** +** Created : 001103 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "tqsql_psql.h" +#include + +#include + +#include +#include +#include +#include +// PostgreSQL header included by redefines DEBUG. +#if defined(DEBUG) +# undef DEBUG +#endif +#include +#include +// PostgreSQL header redefines errno erroneously. +#if defined(errno) +# undef errno +#endif +#define errno qt_psql_errno +#include +#undef errno +#ifdef open +# undef open +#endif + +TQPtrDict *tqSqlDriverExtDict(); +TQPtrDict *tqSqlOpenExtDict(); + +class TQPSQLPrivate +{ +public: + TQPSQLPrivate():connection(0), result(0), isUtf8(FALSE) {} + PGconn *connection; + PGresult *result; + bool isUtf8; +}; + +class TQPSQLDriverExtension : public TQSqlDriverExtension +{ +public: + TQPSQLDriverExtension( TQPSQLDriver *dri ) + : TQSqlDriverExtension(), driver(dri) { } + ~TQPSQLDriverExtension() {} + + bool isOpen() const; +private: + TQPSQLDriver *driver; +}; + +bool TQPSQLDriverExtension::isOpen() const +{ + return PQstatus( driver->connection() ) == CONNECTION_OK; +} + +class TQPSQLOpenExtension : public TQSqlOpenExtension +{ +public: + TQPSQLOpenExtension( TQPSQLDriver *dri ) + : TQSqlOpenExtension(), driver(dri) { } + ~TQPSQLOpenExtension() {} + + bool open( const TQString& db, + const TQString& user, + const TQString& password, + const TQString& host, + int port, + const TQString& connOpts ); +private: + TQPSQLDriver *driver; +}; + +bool TQPSQLOpenExtension::open( const TQString& db, + const TQString& user, + const TQString& password, + const TQString& host, + int port, + const TQString& connOpts ) +{ + return driver->open( db, user, password, host, port, connOpts ); +} + +static TQSqlError qMakeError( const TQString& err, int type, const TQPSQLPrivate* p ) +{ + const char *s = PQerrorMessage(p->connection); + TQString msg = p->isUtf8 ? TQString::fromUtf8(s) : TQString::fromLocal8Bit(s); + return TQSqlError("TQPSQL: " + err, msg, type); +} + +static TQVariant::Type qDecodePSQLType( int t ) +{ + TQVariant::Type type = TQVariant::Invalid; + switch ( t ) { + case BOOLOID : + type = TQVariant::Bool; + break; + case INT8OID : + type = TQVariant::LongLong; + break; + case INT2OID : + // case INT2VECTOROID : // 7.x + case INT4OID : + type = TQVariant::Int; + break; + case NUMERICOID : + case FLOAT4OID : + case FLOAT8OID : + type = TQVariant::Double; + break; +#ifdef ABSTIMEOID // PostgreSQL << 12.x + case ABSTIMEOID : + case RELTIMEOID : +#endif + case DATEOID : + type = TQVariant::Date; + break; + case TIMEOID : +#ifdef TIMETZOID // 7.x + case TIMETZOID : +#endif + type = TQVariant::Time; + break; + case TIMESTAMPOID : +#ifdef DATETIMEOID + // Postgres 6.x datetime workaround. + // DATETIMEOID == TIMESTAMPOID (only the names have changed) + case DATETIMEOID : +#endif +#ifdef TIMESTAMPTZOID + // Postgres 7.2 workaround + // TIMESTAMPTZOID == TIMESTAMPOID == DATETIMEOID + case TIMESTAMPTZOID : +#endif + type = TQVariant::DateTime; + break; + // case ZPBITOID : // 7.x + // case VARBITOID : // 7.x + case OIDOID : + case BYTEAOID : + type = TQVariant::ByteArray; + break; + case REGPROCOID : + case TIDOID : + case XIDOID : + case CIDOID : + // case OIDVECTOROID : // 7.x + case UNKNOWNOID : + // case TINTERVALOID : // 7.x + type = TQVariant::Invalid; + break; + default: + case CHAROID : + case BPCHAROID : + // case LZTEXTOID : // 7.x + case VARCHAROID : + case TEXTOID : + case NAMEOID : + case CASHOID : + case INETOID : + case CIDROID : + case CIRCLEOID : + type = TQVariant::String; + break; + } + return type; +} + +TQPSQLResult::TQPSQLResult( const TQPSQLDriver* db, const TQPSQLPrivate* p ) +: TQSqlResult( db ), + currentSize( 0 ) +{ + d = new TQPSQLPrivate(); + (*d) = (*p); +} + +TQPSQLResult::~TQPSQLResult() +{ + cleanup(); + delete d; +} + +PGresult* TQPSQLResult::result() +{ + return d->result; +} + +void TQPSQLResult::cleanup() +{ + if ( d->result ) + PQclear( d->result ); + d->result = 0; + setAt( -1 ); + currentSize = 0; + setActive( FALSE ); +} + +bool TQPSQLResult::fetch( int i ) +{ + if ( !isActive() ) + return FALSE; + if ( i < 0 ) + return FALSE; + if ( i >= currentSize ) + return FALSE; + if ( at() == i ) + return TRUE; + setAt( i ); + return TRUE; +} + +bool TQPSQLResult::fetchFirst() +{ + return fetch( 0 ); +} + +bool TQPSQLResult::fetchLast() +{ + return fetch( PQntuples( d->result ) - 1 ); +} + +// some Postgres conversions +static TQPoint pointFromString( const TQString& s) +{ + // format '(x,y)' + int pivot = s.find( ',' ); + if ( pivot != -1 ) { + int x = s.mid( 1, pivot-1 ).toInt(); + int y = s.mid( pivot+1, s.length()-pivot-2 ).toInt(); + return TQPoint( x, y ) ; + } else + return TQPoint(); +} + +TQVariant TQPSQLResult::data( int i ) +{ + if ( i >= PQnfields( d->result ) ) { + tqWarning( "TQPSQLResult::data: column %d out of range", i ); + return TQVariant(); + } + int ptype = PQftype( d->result, i ); + TQVariant::Type type = qDecodePSQLType( ptype ); + const TQString val = ( d->isUtf8 && ptype != BYTEAOID ) ? + TQString::fromUtf8( PQgetvalue( d->result, at(), i ) ) : + TQString::fromLocal8Bit( PQgetvalue( d->result, at(), i ) ); + if ( PQgetisnull( d->result, at(), i ) ) { + TQVariant v; + v.cast( type ); + return v; + } + switch ( type ) { + case TQVariant::Bool: + { + TQVariant b ( (bool)(val == "t") ); + return ( b ); + } + case TQVariant::String: + return TQVariant( val ); + case TQVariant::LongLong: + if ( val[0] == '-' ) + return TQVariant( val.toLongLong() ); + else + return TQVariant( val.toULongLong() ); + case TQVariant::Int: + return TQVariant( val.toInt() ); + case TQVariant::Double: + if ( ptype == NUMERICOID ) + return TQVariant( val ); + return TQVariant( val.toDouble() ); + case TQVariant::Date: + if ( val.isEmpty() ) { + return TQVariant( TQDate() ); + } else { + return TQVariant( TQDate::fromString( val, TQt::ISODate ) ); + } + case TQVariant::Time: + if ( val.isEmpty() ) + return TQVariant( TQTime() ); + if ( val.at( val.length() - 3 ) == '+' ) + // strip the timezone + return TQVariant( TQTime::fromString( val.left( val.length() - 3 ), TQt::ISODate ) ); + return TQVariant( TQTime::fromString( val, TQt::ISODate ) ); + case TQVariant::DateTime: { + if ( val.length() < 10 ) + return TQVariant( TQDateTime() ); + // remove the timezone + TQString dtval = val; + if ( dtval.at( dtval.length() - 3 ) == '+' ) + dtval.truncate( dtval.length() - 3 ); + // milliseconds are sometimes returned with 2 digits only + if ( dtval.at( dtval.length() - 3 ).isPunct() ) + dtval += '0'; + if ( dtval.isEmpty() ) + return TQVariant( TQDateTime() ); + else + return TQVariant( TQDateTime::fromString( dtval, TQt::ISODate ) ); + } + case TQVariant::Point: + return TQVariant( pointFromString( val ) ); + case TQVariant::Rect: // format '(x,y),(x',y')' + { + int pivot = val.find( "),(" ); + if ( pivot != -1 ) + return TQVariant( TQRect( pointFromString( val.mid(pivot+2,val.length()) ), pointFromString( val.mid(0,pivot+1) ) ) ); + return TQVariant( TQRect() ); + } + case TQVariant::PointArray: // format '((x,y),(x1,y1),...,(xn,yn))' + { + TQRegExp pointPattern("\\([0-9-]*,[0-9-]*\\)"); + int points = val.contains( pointPattern ); + TQPointArray parray( points ); + int idx = 1; + for ( int i = 0; i < points; i++ ){ + int start = val.find( pointPattern, idx ); + int end = -1; + if ( start != -1 ) { + end = val.find( ')', start+1 ); + if ( end != -1 ) { + parray.setPoint( i, pointFromString( val.mid(idx, end-idx+1) ) ); + } + else + parray.setPoint( i, TQPoint() ); + } else { + parray.setPoint( i, TQPoint() ); + break; + } + idx = end+2; + } + return TQVariant( parray ); + } + case TQVariant::ByteArray: { + if ( ptype == BYTEAOID ) { + uint i = 0; + int index = 0; + uint len = val.length(); + static const TQChar backslash( '\\' ); + TQByteArray ba( (int)len ); + while ( i < len ) { + if ( val.at( i ) == backslash ) { + if ( val.at( i + 1 ).isDigit() ) { + ba[ index++ ] = (char)(val.mid( i + 1, 3 ).toInt( 0, 8 )); + i += 4; + } else { + ba[ index++ ] = val.at( i + 1 ); + i += 2; + } + } else { + ba[ index++ ] = val.at( i++ ).unicode(); + } + } + ba.resize( index ); + return TQVariant( ba ); + } + + TQByteArray ba; + ((TQSqlDriver*)driver())->beginTransaction(); + Oid oid = val.toInt(); + int fd = lo_open( d->connection, oid, INV_READ ); +#ifdef QT_CHECK_RANGE + if ( fd < 0) { + tqWarning( "TQPSQLResult::data: unable to open large object for read" ); + ((TQSqlDriver*)driver())->commitTransaction(); + return TQVariant( ba ); + } +#endif + int size = 0; + int retval = lo_lseek( d->connection, fd, 0L, SEEK_END ); + if ( retval >= 0 ) { + size = lo_tell( d->connection, fd ); + lo_lseek( d->connection, fd, 0L, SEEK_SET ); + } + if ( size == 0 ) { + lo_close( d->connection, fd ); + ((TQSqlDriver*)driver())->commitTransaction(); + return TQVariant( ba ); + } + char * buf = new char[ size ]; + +#ifdef Q_OS_WIN32 + // ### For some reason lo_read() fails if we try to read more than + // ### 32760 bytes + char * p = buf; + int nread = 0; + + while( size < nread ){ + retval = lo_read( d->connection, fd, p, 32760 ); + nread += retval; + p += retval; + } +#else + retval = lo_read( d->connection, fd, buf, size ); +#endif + + if (retval < 0) { + tqWarning( "TQPSQLResult::data: unable to read large object" ); + } else { + ba.duplicate( buf, size ); + } + delete [] buf; + lo_close( d->connection, fd ); + ((TQSqlDriver*)driver())->commitTransaction(); + return TQVariant( ba ); + } + default: + case TQVariant::Invalid: +#ifdef QT_CHECK_RANGE + tqWarning("TQPSQLResult::data: unknown data type"); +#endif + ; + } + return TQVariant(); +} + +bool TQPSQLResult::isNull( int field ) +{ + PQgetvalue( d->result, at(), field ); + return PQgetisnull( d->result, at(), field ); +} + +bool TQPSQLResult::reset ( const TQString& query ) +{ + cleanup(); + if ( !driver() ) + return FALSE; + if ( !driver()->isOpen() || driver()->isOpenError() ) + return FALSE; + setActive( FALSE ); + setAt( TQSql::BeforeFirst ); + if ( d->result ) + PQclear( d->result ); + if ( d->isUtf8 ) { + d->result = PQexec( d->connection, query.utf8().data() ); + } else { + d->result = PQexec( d->connection, query.local8Bit().data() ); + } + int status = PQresultStatus( d->result ); + if ( status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK ) { + if ( status == PGRES_TUPLES_OK ) { + setSelect( TRUE ); + currentSize = PQntuples( d->result ); + } else { + setSelect( FALSE ); + currentSize = -1; + } + setActive( TRUE ); + return TRUE; + } + setLastError( qMakeError( "Unable to create query", TQSqlError::Statement, d ) ); + return FALSE; +} + +int TQPSQLResult::size() +{ + return currentSize; +} + +int TQPSQLResult::numRowsAffected() +{ + return TQString( PQcmdTuples( d->result ) ).toInt(); +} + +/////////////////////////////////////////////////////////////////// + +static bool setEncodingUtf8( PGconn* connection ) +{ + PGresult* result = PQexec( connection, "SET CLIENT_ENCODING TO 'UNICODE'" ); + int status = PQresultStatus( result ); + PQclear( result ); + return status == PGRES_COMMAND_OK; +} + +static void setDatestyle( PGconn* connection ) +{ + PGresult* result = PQexec( connection, "SET DATESTYLE TO 'ISO'" ); +#ifdef QT_CHECK_RANGE + int status = PQresultStatus( result ); + if ( status != PGRES_COMMAND_OK ) + tqWarning( "%s", PQerrorMessage( connection ) ); +#endif + PQclear( result ); +} + +static TQPSQLDriver::Protocol getPSQLVersion( PGconn* connection ) +{ + PGresult* result = PQexec( connection, "select version()" ); + int status = PQresultStatus( result ); + if ( status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK ) { + TQString val( PQgetvalue( result, 0, 0 ) ); + PQclear( result ); + TQRegExp rx( "(\\d+)\\.(\\d+)" ); + rx.setMinimal ( TRUE ); // enforce non-greedy RegExp + if ( rx.search( val ) != -1 ) { + int vMaj = rx.cap( 1 ).toInt(); + int vMin = rx.cap( 2 ).toInt(); + if ( vMaj < 6 ) { +#ifdef QT_CHECK_RANGE + tqWarning( "This version of PostgreSQL is not supported and may not work." ); +#endif + return TQPSQLDriver::Version6; + } + if ( vMaj == 6 ) { + return TQPSQLDriver::Version6; + } else if ( vMaj == 7 ) { + if ( vMin < 1 ) + return TQPSQLDriver::Version7; + else if ( vMin < 3 ) + return TQPSQLDriver::Version71; + } + return TQPSQLDriver::Version73; + } + } else { +#ifdef QT_CHECK_RANGE + tqWarning( "This version of PostgreSQL is not supported and may not work." ); +#endif + } + + return TQPSQLDriver::Version6; +} + +TQPSQLDriver::TQPSQLDriver( TQObject * parent, const char * name ) + : TQSqlDriver(parent,name ? name : "TQPSQL"), pro( TQPSQLDriver::Version6 ) +{ + init(); +} + +TQPSQLDriver::TQPSQLDriver( PGconn * conn, TQObject * parent, const char * name ) + : TQSqlDriver(parent,name ? name : "TQPSQL"), pro( TQPSQLDriver::Version6 ) +{ + init(); + d->connection = conn; + if ( conn ) { + pro = getPSQLVersion( d->connection ); + setOpen( TRUE ); + setOpenError( FALSE ); + } +} + +void TQPSQLDriver::init() +{ + tqSqlDriverExtDict()->insert( this, new TQPSQLDriverExtension(this) ); + tqSqlOpenExtDict()->insert( this, new TQPSQLOpenExtension(this) ); + + d = new TQPSQLPrivate(); +} + +TQPSQLDriver::~TQPSQLDriver() +{ + if ( d->connection ) + PQfinish( d->connection ); + delete d; + if ( !tqSqlDriverExtDict()->isEmpty() ) { + TQSqlDriverExtension *ext = tqSqlDriverExtDict()->take( this ); + delete ext; + } + if ( !tqSqlOpenExtDict()->isEmpty() ) { + TQSqlOpenExtension *ext = tqSqlOpenExtDict()->take( this ); + delete ext; + } +} + +PGconn* TQPSQLDriver::connection() +{ + return d->connection; +} + + +bool TQPSQLDriver::hasFeature( DriverFeature f ) const +{ + switch ( f ) { + case Transactions: + return TRUE; + case QuerySize: + return TRUE; + case BLOB: + return pro >= TQPSQLDriver::Version71; + case Unicode: + return d->isUtf8; + default: + return FALSE; + } +} + +bool TQPSQLDriver::open( const TQString&, + const TQString&, + const TQString&, + const TQString&, + int ) +{ + tqWarning("TQPSQLDriver::open(): This version of open() is no longer supported." ); + return FALSE; +} + +bool TQPSQLDriver::open( const TQString & db, + const TQString & user, + const TQString & password, + const TQString & host, + int port, + const TQString& connOpts ) +{ + if ( isOpen() ) + close(); + TQString connectString; + if ( host.length() ) + connectString.append( "host=" ).append( host ); + if ( db.length() ) + connectString.append( " dbname=" ).append( db ); + if ( user.length() ) + connectString.append( " user=" ).append( user ); + if ( password.length() ) + connectString.append( " password=" ).append( password ); + if ( port > -1 ) + connectString.append( " port=" ).append( TQString::number( port ) ); + + // add any connect options - the server will handle error detection + if ( !connOpts.isEmpty() ) + connectString += " " + TQStringList::split( ';', connOpts ).join( " " ); + + d->connection = PQconnectdb( connectString.local8Bit().data() ); + if ( PQstatus( d->connection ) == CONNECTION_BAD ) { + setLastError( qMakeError("Unable to connect", TQSqlError::Connection, d ) ); + setOpenError( TRUE ); + return FALSE; + } + + pro = getPSQLVersion( d->connection ); + d->isUtf8 = setEncodingUtf8( d->connection ); + setDatestyle( d->connection ); + + setOpen( TRUE ); + setOpenError( FALSE ); + return TRUE; +} + +void TQPSQLDriver::close() +{ + if ( isOpen() ) { + if (d->connection) + PQfinish( d->connection ); + d->connection = 0; + setOpen( FALSE ); + setOpenError( FALSE ); + } +} + +bool TQPSQLDriver::ping() +{ + if ( !isOpen() ) { + return FALSE; + } + + PGresult *res = NULL; + + // Send ping + res = PQexec( d->connection, "" ); + PQclear(res); + + // Check connection status + if ( PQstatus( d->connection ) != CONNECTION_OK ) { + PQreset( d->connection ); + if ( PQstatus( d->connection ) != CONNECTION_OK ) { + setLastError( qMakeError("Unable to execute ping", TQSqlError::Statement, d ) ); + return FALSE; + } + } + return TRUE; +} + +TQSqlQuery TQPSQLDriver::createQuery() const +{ + return TQSqlQuery( new TQPSQLResult( this, d ) ); +} + +bool TQPSQLDriver::beginTransaction() +{ + if ( !isOpen() ) { +#ifdef QT_CHECK_RANGE + tqWarning( "TQPSQLDriver::beginTransaction: Database not open" ); +#endif + return FALSE; + } + PGresult* res = PQexec( d->connection, "BEGIN" ); + if ( !res || PQresultStatus( res ) != PGRES_COMMAND_OK ) { + PQclear( res ); + setLastError( qMakeError( "Could not begin transaction", TQSqlError::Transaction, d ) ); + return FALSE; + } + PQclear( res ); + return TRUE; +} + +bool TQPSQLDriver::commitTransaction() +{ + if ( !isOpen() ) { +#ifdef QT_CHECK_RANGE + tqWarning( "TQPSQLDriver::commitTransaction: Database not open" ); +#endif + return FALSE; + } + PGresult* res = PQexec( d->connection, "COMMIT" ); + if ( !res || PQresultStatus( res ) != PGRES_COMMAND_OK ) { + PQclear( res ); + setLastError( qMakeError( "Could not commit transaction", TQSqlError::Transaction, d ) ); + return FALSE; + } + PQclear( res ); + return TRUE; +} + +bool TQPSQLDriver::rollbackTransaction() +{ + if ( !isOpen() ) { +#ifdef QT_CHECK_RANGE + tqWarning( "TQPSQLDriver::rollbackTransaction: Database not open" ); +#endif + return FALSE; + } + PGresult* res = PQexec( d->connection, "ROLLBACK" ); + if ( !res || PQresultStatus( res ) != PGRES_COMMAND_OK ) { + setLastError( qMakeError( "Could not rollback transaction", TQSqlError::Transaction, d ) ); + PQclear( res ); + return FALSE; + } + PQclear( res ); + return TRUE; +} + +TQStringList TQPSQLDriver::tables( const TQString& typeName ) const +{ + TQStringList tl; + if ( !isOpen() ) + return tl; + int type = typeName.toInt(); + TQSqlQuery t = createQuery(); + t.setForwardOnly( TRUE ); + + if ( typeName.isEmpty() || ((type & (int)TQSql::Tables) == (int)TQSql::Tables) ) { + + TQString query("select relname from pg_class where (relkind = 'r') " + "and (relname !~ '^Inv') " + "and (relname !~ '^pg_') "); + if (pro >= TQPSQLDriver::Version73) + query.append("and (relnamespace not in " + "(select oid from pg_namespace where nspname = 'information_schema')) " + "and pg_table_is_visible(pg_class.oid) "); + t.exec(query); + while ( t.next() ) + tl.append( t.value(0).toString() ); + } + if ( (type & (int)TQSql::Views) == (int)TQSql::Views ) { + TQString query("select relname from pg_class where ( relkind = 'v' ) " + "and ( relname !~ '^Inv' ) " + "and ( relname !~ '^pg_' ) "); + if (pro >= TQPSQLDriver::Version73) + query.append("and (relnamespace not in " + "(select oid from pg_namespace where nspname = 'information_schema')) " + "and pg_table_is_visible(pg_class.oid) "); + t.exec(query); + while ( t.next() ) + tl.append( t.value(0).toString() ); + } + if ( (type & (int)TQSql::SystemTables) == (int)TQSql::SystemTables ) { + TQString query( "select relname from pg_class where ( relkind = 'r' ) " + "and ( relname like 'pg_%' ) " ); + if (pro >= TQPSQLDriver::Version73) + query.append( "and pg_table_is_visible(pg_class.oid) " ); + t.exec(query); + while ( t.next() ) + tl.append( t.value(0).toString() ); + } + + return tl; +} + +TQSqlIndex TQPSQLDriver::primaryIndex( const TQString& tablename ) const +{ + TQSqlIndex idx( tablename ); + if ( !isOpen() ) + return idx; + TQSqlQuery i = createQuery(); + TQString stmt; + + switch( pro ) { + case TQPSQLDriver::Version6: + stmt = "select pg_att1.attname, int(pg_att1.atttypid), pg_att2.attnum, pg_cl.relname " + "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind " + "where lower(pg_cl.relname) = '%1_pkey' "; + break; + case TQPSQLDriver::Version7: + case TQPSQLDriver::Version71: + stmt = "select pg_att1.attname, pg_att1.atttypid::int, pg_cl.relname " + "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind " + "where lower(pg_cl.relname) = '%1_pkey' "; + break; + case TQPSQLDriver::Version73: + stmt = "select pg_att1.attname, pg_att1.atttypid::int, pg_cl.relname " + "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind " + "where lower(pg_cl.relname) = '%1_pkey' " + "and pg_table_is_visible(pg_cl.oid) " + "and pg_att1.attisdropped = false "; + break; + } + stmt += "and pg_cl.oid = pg_ind.indexrelid " + "and pg_att2.attrelid = pg_ind.indexrelid " + "and pg_att1.attrelid = pg_ind.indrelid " + "and pg_att1.attnum = pg_ind.indkey[pg_att2.attnum-1] " + "order by pg_att2.attnum"; + + i.exec( stmt.arg( tablename.lower() ) ); + while ( i.isActive() && i.next() ) { + TQSqlField f( i.value(0).toString(), qDecodePSQLType( i.value(1).toInt() ) ); + idx.append( f ); + idx.setName( i.value(2).toString() ); + } + return idx; +} + +TQSqlRecord TQPSQLDriver::record( const TQString& tablename ) const +{ + TQSqlRecord fil; + if ( !isOpen() ) + return fil; + TQString stmt; + switch( pro ) { + case TQPSQLDriver::Version6: + stmt = "select pg_attribute.attname, int(pg_attribute.atttypid) " + "from pg_class, pg_attribute " + "where lower(pg_class.relname) = '%1' " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attrelid = pg_class.oid "; + break; + case TQPSQLDriver::Version7: + case TQPSQLDriver::Version71: + stmt = "select pg_attribute.attname, pg_attribute.atttypid::int " + "from pg_class, pg_attribute " + "where lower(pg_class.relname) = '%1' " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attrelid = pg_class.oid "; + break; + case TQPSQLDriver::Version73: + stmt = "select pg_attribute.attname, pg_attribute.atttypid::int " + "from pg_class, pg_attribute " + "where lower(pg_class.relname) = '%1' " + "and pg_table_is_visible(pg_class.oid) " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attisdropped = false " + "and pg_attribute.attrelid = pg_class.oid "; + break; + } + + TQSqlQuery fi = createQuery(); + fi.exec( stmt.arg( tablename.lower() ) ); + while ( fi.next() ) { + TQSqlField f( fi.value(0).toString(), qDecodePSQLType( fi.value(1).toInt() ) ); + fil.append( f ); + } + return fil; +} + +TQSqlRecord TQPSQLDriver::record( const TQSqlQuery& query ) const +{ + TQSqlRecord fil; + if ( !isOpen() ) + return fil; + if ( query.isActive() && query.driver() == this ) { + TQPSQLResult* result = (TQPSQLResult*)query.result(); + int count = PQnfields( result->d->result ); + for ( int i = 0; i < count; ++i ) { + TQString name = PQfname( result->d->result, i ); + TQVariant::Type type = qDecodePSQLType( PQftype( result->d->result, i ) ); + TQSqlField rf( name, type ); + fil.append( rf ); + } + } + return fil; +} + +TQSqlRecordInfo TQPSQLDriver::recordInfo( const TQString& tablename ) const +{ + TQSqlRecordInfo info; + if ( !isOpen() ) + return info; + + TQString stmt; + switch( pro ) { + case TQPSQLDriver::Version6: + stmt = "select pg_attribute.attname, int(pg_attribute.atttypid), pg_attribute.attnotnull, " + "pg_attribute.attlen, pg_attribute.atttypmod, int(pg_attribute.attrelid), pg_attribute.attnum " + "from pg_class, pg_attribute " + "where lower(pg_class.relname) = '%1' " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attrelid = pg_class.oid "; + break; + case TQPSQLDriver::Version7: + stmt = "select pg_attribute.attname, pg_attribute.atttypid::int, pg_attribute.attnotnull, " + "pg_attribute.attlen, pg_attribute.atttypmod, pg_attribute.attrelid::int, pg_attribute.attnum " + "from pg_class, pg_attribute " + "where lower(pg_class.relname) = '%1' " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attrelid = pg_class.oid "; + break; + case TQPSQLDriver::Version71: + stmt = "select pg_attribute.attname, pg_attribute.atttypid::int, pg_attribute.attnotnull, " + "pg_attribute.attlen, pg_attribute.atttypmod, pg_attrdef.adsrc " + "from pg_class, pg_attribute " + "left join pg_attrdef on (pg_attrdef.adrelid = pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) " + "where lower(pg_class.relname) = '%1' " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attrelid = pg_class.oid " + "order by pg_attribute.attnum "; + break; + case TQPSQLDriver::Version73: + stmt = "select pg_attribute.attname, pg_attribute.atttypid::int, pg_attribute.attnotnull, " + "pg_attribute.attlen, pg_attribute.atttypmod, pg_attrdef.adsrc " + "from pg_class, pg_attribute " + "left join pg_attrdef on (pg_attrdef.adrelid = pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) " + "where lower(pg_class.relname) = '%1' " + "and pg_table_is_visible(pg_class.oid) " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attrelid = pg_class.oid " + "and pg_attribute.attisdropped = false " + "order by pg_attribute.attnum "; + break; + } + + TQSqlQuery query = createQuery(); + query.exec( stmt.arg( tablename.lower() ) ); + if ( pro >= TQPSQLDriver::Version71 ) { + while ( query.next() ) { + int len = query.value( 3 ).toInt(); + int precision = query.value( 4 ).toInt(); + // swap length and precision if length == -1 + if ( len == -1 && precision > -1 ) { + len = precision - 4; + precision = -1; + } + TQString defVal = query.value( 5 ).toString(); + if ( !defVal.isEmpty() && defVal.startsWith( "'" ) ) + defVal = defVal.mid( 1, defVal.length() - 2 ); + info.append( TQSqlFieldInfo( query.value( 0 ).toString(), + qDecodePSQLType( query.value( 1 ).toInt() ), + query.value( 2 ).toBool(), + len, + precision, + defVal, + query.value( 1 ).toInt() ) ); + } + } else { + // Postgres < 7.1 cannot handle outer joins + while ( query.next() ) { + TQString defVal; + TQString stmt2 = "select pg_attrdef.adsrc from pg_attrdef where " + "pg_attrdef.adrelid = %1 and pg_attrdef.adnum = %2 "; + TQSqlQuery query2 = createQuery(); + query2.exec( stmt2.arg( query.value( 5 ).toInt() ).arg( query.value( 6 ).toInt() ) ); + if ( query2.isActive() && query2.next() ) + defVal = query2.value( 0 ).toString(); + if ( !defVal.isEmpty() && defVal.startsWith( "'" ) ) + defVal = defVal.mid( 1, defVal.length() - 2 ); + int len = query.value( 3 ).toInt(); + int precision = query.value( 4 ).toInt(); + // swap length and precision if length == -1 + if ( len == -1 && precision > -1 ) { + len = precision - 4; + precision = -1; + } + info.append( TQSqlFieldInfo( query.value( 0 ).toString(), + qDecodePSQLType( query.value( 1 ).toInt() ), + query.value( 2 ).toBool(), + len, + precision, + defVal, + query.value( 1 ).toInt() ) ); + } + } + + return info; +} + +TQSqlRecordInfo TQPSQLDriver::recordInfo( const TQSqlQuery& query ) const +{ + TQSqlRecordInfo info; + if ( !isOpen() ) + return info; + if ( query.isActive() && query.driver() == this ) { + TQPSQLResult* result = (TQPSQLResult*)query.result(); + int count = PQnfields( result->d->result ); + for ( int i = 0; i < count; ++i ) { + TQString name = PQfname( result->d->result, i ); + int len = PQfsize( result->d->result, i ); + int precision = PQfmod( result->d->result, i ); + // swap length and precision if length == -1 + if ( len == -1 && precision > -1 ) { + len = precision - 4; + precision = -1; + } + info.append( TQSqlFieldInfo( name, + qDecodePSQLType( PQftype( result->d->result, i ) ), + -1, + len, + precision, + TQVariant(), + PQftype( result->d->result, i ) ) ); + } + } + return info; +} + +TQString TQPSQLDriver::formatValue( const TQSqlField* field, + bool ) const +{ + TQString r; + if ( field->isNull() ) { + r = nullText(); + } else { + switch ( field->type() ) { + case TQVariant::DateTime: + if ( field->value().toDateTime().isValid() ) { + TQDate dt = field->value().toDateTime().date(); + TQTime tm = field->value().toDateTime().time(); + // msecs need to be right aligned otherwise psql + // interpretes them wrong + r = "'" + TQString::number( dt.year() ) + "-" + + TQString::number( dt.month() ) + "-" + + TQString::number( dt.day() ) + " " + + tm.toString() + "." + + TQString::number( tm.msec() ).rightJustify( 3, '0' ) + "'"; + } else { + r = nullText(); + } + break; + case TQVariant::Time: + if ( field->value().toTime().isValid() ) { + r = field->value().toTime().toString( TQt::ISODate ); + } else { + r = nullText(); + } + case TQVariant::String: + case TQVariant::CString: { + switch ( field->value().type() ) { + case TQVariant::Rect: { + TQRect rec = field->value().toRect(); + // upper right corner then lower left according to psql docs + r = "'(" + TQString::number( rec.right() ) + + "," + TQString::number( rec.bottom() ) + + "),(" + TQString::number( rec.left() ) + + "," + TQString::number( rec.top() ) + ")'"; + break; + } + case TQVariant::Point: { + TQPoint p = field->value().toPoint(); + r = "'(" + TQString::number( p.x() ) + + "," + TQString::number( p.y() ) + ")'"; + break; + } + case TQVariant::PointArray: { + TQPointArray pa = field->value().toPointArray(); + r = "' "; + for ( int i = 0; i < (int)pa.size(); ++i ) { + r += "(" + TQString::number( pa[i].x() ) + + "," + TQString::number( pa[i].y() ) + "),"; + } + r.truncate( r.length() - 1 ); + r += "'"; + break; + } + default: + // Escape '\' characters + r = TQSqlDriver::formatValue( field ); + r.replace( "\\", "\\\\" ); + break; + } + break; + } + case TQVariant::Bool: + if ( field->value().toBool() ) + r = "TRUE"; + else + r = "FALSE"; + break; + case TQVariant::ByteArray: { + TQByteArray ba = field->value().asByteArray(); + TQString res; + r = "'"; + unsigned char uc; + for ( int i = 0; i < (int)ba.size(); ++i ) { + uc = (unsigned char) ba[ i ]; + if ( uc > 40 && uc < 92 ) { + r += uc; + } else { + r += "\\\\"; + r += TQString::number( (unsigned char) ba[ i ], 8 ).rightJustify( 3, '0', TRUE ); + } + } + r += "'"; + break; + } + default: + r = TQSqlDriver::formatValue( field ); + break; + } + } + return r; +} diff --git a/src/sql/drivers/psql/tqsql_psql.h b/src/sql/drivers/psql/tqsql_psql.h new file mode 100644 index 000000000..61f30a581 --- /dev/null +++ b/src/sql/drivers/psql/tqsql_psql.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Definition of PostgreSQL driver classes +** +** Created : 001103 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef TQSQL_PSQL_H +#define TQSQL_PSQL_H + +#include +#include +#include +#include + +#ifdef QT_PLUGIN +#define Q_EXPORT_SQLDRIVER_PSQL +#else +#define Q_EXPORT_SQLDRIVER_PSQL TQ_EXPORT +#endif + +class TQPSQLPrivate; +class TQPSQLDriver; +class TQSqlRecordInfo; + +class TQPSQLResult : public TQSqlResult +{ + friend class TQPSQLDriver; +public: + TQPSQLResult( const TQPSQLDriver* db, const TQPSQLPrivate* p ); + ~TQPSQLResult(); + PGresult* result(); +protected: + void cleanup(); + bool fetch( int i ); + bool fetchFirst(); + bool fetchLast(); + TQVariant data( int i ); + bool isNull( int field ); + bool reset ( const TQString& query ); + int size(); + int numRowsAffected(); +private: + int currentSize; + TQPSQLPrivate* d; +}; + +class Q_EXPORT_SQLDRIVER_PSQL TQPSQLDriver : public TQSqlDriver +{ +public: + enum Protocol { + Version6 = 6, + Version7 = 7, + Version71 = 8, + Version73 = 9 + }; + + TQPSQLDriver( TQObject * parent=0, const char * name=0 ); + TQPSQLDriver( PGconn * conn, TQObject * parent=0, const char * name=0 ); + ~TQPSQLDriver(); + bool hasFeature( DriverFeature f ) const; + bool open( const TQString & db, + const TQString & user = TQString::null, + const TQString & password = TQString::null, + const TQString & host = TQString::null, + int port = -1 ); + void close(); + bool ping(); + TQSqlQuery createQuery() const; + TQStringList tables( const TQString& user ) const; + TQSqlIndex primaryIndex( const TQString& tablename ) const; + TQSqlRecord record( const TQString& tablename ) const; + TQSqlRecord record( const TQSqlQuery& query ) const; + TQSqlRecordInfo recordInfo( const TQString& tablename ) const; + TQSqlRecordInfo recordInfo( const TQSqlQuery& query ) const; + + Protocol protocol() const { return pro; } + PGconn* connection(); + TQString formatValue( const TQSqlField* field, + bool trimStrings ) const; + + // ### remove me for 4.0 + bool open( const TQString& db, + const TQString& user, + const TQString& password, + const TQString& host, + int port, + const TQString& connOpts ); +protected: + bool beginTransaction(); + bool commitTransaction(); + bool rollbackTransaction(); +private: + void init(); + Protocol pro; + TQPSQLPrivate* d; +}; + +#endif -- cgit v1.2.3