diff options
Diffstat (limited to 'tqtinterface/qt4/src/sql/drivers/psql/tqsql_psql.cpp')
-rw-r--r-- | tqtinterface/qt4/src/sql/drivers/psql/tqsql_psql.cpp | 1117 |
1 files changed, 0 insertions, 1117 deletions
diff --git a/tqtinterface/qt4/src/sql/drivers/psql/tqsql_psql.cpp b/tqtinterface/qt4/src/sql/drivers/psql/tqsql_psql.cpp deleted file mode 100644 index 7809749..0000000 --- a/tqtinterface/qt4/src/sql/drivers/psql/tqsql_psql.cpp +++ /dev/null @@ -1,1117 +0,0 @@ -/**************************************************************************** -** -** Implementation of PostgreSQL driver classes -** -** Created : 001103 -** -** Copyright (C) 2010 Timothy Pearson and (C) 1992-2008 Trolltech ASA. -** -** 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 <private/tqsqlextension_p.h> - -#include <math.h> - -#include <tqpointarray.h> -#include <tqsqlrecord.h> -#include <tqregexp.h> -#include <tqdatetime.h> -// PostgreSQL header <utils/elog.h> included by <postgres.h> redefines DEBUG. -#if defined(DEBUG) -# undef DEBUG -#endif -#include <postgres.h> -#include <libpq/libpq-fs.h> -// PostgreSQL header <catalog/pg_type.h> redefines errno erroneously. -#if defined(errno) -# undef errno -#endif -#define errno qt_psql_errno -#include <catalog/pg_type.h> -#undef errno -#ifdef open -# undef open -#endif - -TQPtrDict<TQSqlDriverExtension> *qSqlDriverExtDict(); -TQPtrDict<TQSqlOpenExtension> *qSqlOpenExtDict(); - -class TQPSTQLPrivate -{ -public: - TQPSTQLPrivate():connection(0), result(0), isUtf8(FALSE) {} - PGconn *connection; - PGresult *result; - bool isUtf8; -}; - -class TQPSTQLDriverExtension : public TQSqlDriverExtension -{ -public: - TQPSTQLDriverExtension( TQPSTQLDriver *dri ) - : TQSqlDriverExtension(), driver(dri) { } - ~TQPSTQLDriverExtension() {} - - bool isOpen() const; -private: - TQPSTQLDriver *driver; -}; - -bool TQPSTQLDriverExtension::isOpen() const -{ - return PQstatus( driver->connection() ) == CONNECTION_OK; -} - -class TQPSTQLOpenExtension : public TQSqlOpenExtension -{ -public: - TQPSTQLOpenExtension( TQPSTQLDriver *dri ) - : TQSqlOpenExtension(), driver(dri) { } - ~TQPSTQLOpenExtension() {} - - bool open( const TQString& db, - const TQString& user, - const TQString& password, - const TQString& host, - int port, - const TQString& connOpts ); -private: - TQPSTQLDriver *driver; -}; - -bool TQPSTQLOpenExtension::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 TQPSTQLPrivate* 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 qDecodePSTQLType( 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; - case ABSTIMEOID : - case RELTIMEOID : - 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; -} - -TQPSTQLResult::TQPSTQLResult( const TQPSTQLDriver* db, const TQPSTQLPrivate* p ) -: TQSqlResult( db ), - currentSize( 0 ) -{ - d = new TQPSTQLPrivate(); - (*d) = (*p); -} - -TQPSTQLResult::~TQPSTQLResult() -{ - cleanup(); - delete d; -} - -PGresult* TQPSTQLResult::result() -{ - return d->result; -} - -void TQPSTQLResult::cleanup() -{ - if ( d->result ) - PQclear( d->result ); - d->result = 0; - setAt( -1 ); - currentSize = 0; - setActive( FALSE ); -} - -bool TQPSTQLResult::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 TQPSTQLResult::fetchFirst() -{ - return fetch( 0 ); -} - -bool TQPSTQLResult::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 TQPSTQLResult::data( int i ) -{ - if ( i >= PQnfields( d->result ) ) { - qWarning( "TQPSTQLResult::data: column %d out of range", i ); - return TQVariant(); - } - int ptype = PQftype( d->result, i ); - TQVariant::Type type = qDecodePSTQLType( 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"), 0 ); - 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++ ).tqunicode(); - } - } - 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 TQT_CHECK_RANGE - if ( fd < 0) { - qWarning( "TQPSTQLResult::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 TQ_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) { - qWarning( "TQPSTQLResult::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 TQT_CHECK_RANGE - qWarning("TQPSTQLResult::data: unknown data type"); -#endif - ; - } - return TQVariant(); -} - -bool TQPSTQLResult::isNull( int field ) -{ - PQgetvalue( d->result, at(), field ); - return PQgetisnull( d->result, at(), field ); -} - -bool TQPSTQLResult::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 = PQresultqStatus( 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 TQPSTQLResult::size() -{ - return currentSize; -} - -int TQPSTQLResult::numRowsAffected() -{ - return TQString( PQcmdTuples( d->result ) ).toInt(); -} - -/////////////////////////////////////////////////////////////////// - -static bool setEncodingUtf8( PGconn* connection ) -{ - PGresult* result = PQexec( connection, "SET CLIENT_ENCODING TO 'UNICODE'" ); - int status = PQresultqStatus( result ); - PQclear( result ); - return status == PGRES_COMMAND_OK; -} - -static void setDatestyle( PGconn* connection ) -{ - PGresult* result = PQexec( connection, "SET DATESTYLE TO 'ISO'" ); -#ifdef TQT_CHECK_RANGE - int status = PQresultqStatus( result ); - if ( status != PGRES_COMMAND_OK ) - qWarning( "%s", PQerrorMessage( connection ) ); -#endif - PQclear( result ); -} - -static TQPSTQLDriver::Protocol getPSTQLVersion( PGconn* connection ) -{ - PGresult* result = PQexec( connection, "select version()" ); - int status = PQresultqStatus( 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 TQT_CHECK_RANGE - qWarning( "This version of PostgreSQL is not supported and may not work." ); -#endif - return TQPSTQLDriver::Version6; - } - if ( vMaj == 6 ) { - return TQPSTQLDriver::Version6; - } else if ( vMaj == 7 ) { - if ( vMin < 1 ) - return TQPSTQLDriver::Version7; - else if ( vMin < 3 ) - return TQPSTQLDriver::Version71; - } - return TQPSTQLDriver::Version73; - } - } else { -#ifdef TQT_CHECK_RANGE - qWarning( "This version of PostgreSQL is not supported and may not work." ); -#endif - } - - return TQPSTQLDriver::Version6; -} - -TQPSTQLDriver::TQPSTQLDriver( TQObject * parent, const char * name ) - : TQSqlDriver(parent,name ? name : "TQPSQL"), pro( TQPSTQLDriver::Version6 ) -{ - init(); -} - -TQPSTQLDriver::TQPSTQLDriver( PGconn * conn, TQObject * parent, const char * name ) - : TQSqlDriver(parent,name ? name : "TQPSQL"), pro( TQPSTQLDriver::Version6 ) -{ - init(); - d->connection = conn; - if ( conn ) { - pro = getPSTQLVersion( d->connection ); - setOpen( TRUE ); - setOpenError( FALSE ); - } -} - -void TQPSTQLDriver::init() -{ - qSqlDriverExtDict()->insert( this, new TQPSTQLDriverExtension(this) ); - qSqlOpenExtDict()->insert( this, new TQPSTQLOpenExtension(this) ); - - d = new TQPSTQLPrivate(); -} - -TQPSTQLDriver::~TQPSTQLDriver() -{ - if ( d->connection ) - PQfinish( d->connection ); - delete d; - if ( !qSqlDriverExtDict()->isEmpty() ) { - TQSqlDriverExtension *ext = qSqlDriverExtDict()->take( this ); - delete ext; - } - if ( !qSqlOpenExtDict()->isEmpty() ) { - TQSqlOpenExtension *ext = qSqlOpenExtDict()->take( this ); - delete ext; - } -} - -PGconn* TQPSTQLDriver::connection() -{ - return d->connection; -} - - -bool TQPSTQLDriver::hasFeature( DriverFeature f ) const -{ - switch ( f ) { - case Transactions: - return TRUE; - case QuerySize: - return TRUE; - case BLOB: - return pro >= TQPSTQLDriver::Version71; - case Unicode: - return d->isUtf8; - default: - return FALSE; - } -} - -bool TQPSTQLDriver::open( const TQString&, - const TQString&, - const TQString&, - const TQString&, - int ) -{ - qWarning("TQPSTQLDriver::open(): This version of open() is no longer supported." ); - return FALSE; -} - -bool TQPSTQLDriver::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 = getPSTQLVersion( d->connection ); - d->isUtf8 = setEncodingUtf8( d->connection ); - setDatestyle( d->connection ); - - setOpen( TRUE ); - setOpenError( FALSE ); - return TRUE; -} - -void TQPSTQLDriver::close() -{ - if ( isOpen() ) { - if (d->connection) - PQfinish( d->connection ); - d->connection = 0; - setOpen( FALSE ); - setOpenError( FALSE ); - } -} - -TQSqlQuery TQPSTQLDriver::createQuery() const -{ - return TQSqlQuery( new TQPSTQLResult( this, d ) ); -} - -bool TQPSTQLDriver::beginTransaction() -{ - if ( !isOpen() ) { -#ifdef TQT_CHECK_RANGE - qWarning( "TQPSTQLDriver::beginTransaction: Database not open" ); -#endif - return FALSE; - } - PGresult* res = PQexec( d->connection, "BEGIN" ); - if ( !res || PQresultqStatus( res ) != PGRES_COMMAND_OK ) { - PQclear( res ); - setLastError( qMakeError( "Could not begin transaction", TQSqlError::Transaction, d ) ); - return FALSE; - } - PQclear( res ); - return TRUE; -} - -bool TQPSTQLDriver::commitTransaction() -{ - if ( !isOpen() ) { -#ifdef TQT_CHECK_RANGE - qWarning( "TQPSTQLDriver::commitTransaction: Database not open" ); -#endif - return FALSE; - } - PGresult* res = PQexec( d->connection, "COMMIT" ); - if ( !res || PQresultqStatus( res ) != PGRES_COMMAND_OK ) { - PQclear( res ); - setLastError( qMakeError( "Could not commit transaction", TQSqlError::Transaction, d ) ); - return FALSE; - } - PQclear( res ); - return TRUE; -} - -bool TQPSTQLDriver::rollbackTransaction() -{ - if ( !isOpen() ) { -#ifdef TQT_CHECK_RANGE - qWarning( "TQPSTQLDriver::rollbackTransaction: Database not open" ); -#endif - return FALSE; - } - PGresult* res = PQexec( d->connection, "ROLLBACK" ); - if ( !res || PQresultqStatus( res ) != PGRES_COMMAND_OK ) { - setLastError( qMakeError( "Could not rollback transaction", TQSqlError::Transaction, d ) ); - PQclear( res ); - return FALSE; - } - PQclear( res ); - return TRUE; -} - -TQStringList TQPSTQLDriver::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 >= TQPSTQLDriver::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 >= TQPSTQLDriver::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 >= TQPSTQLDriver::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 TQPSTQLDriver::primaryIndex( const TQString& tablename ) const -{ - TQSqlIndex idx( tablename ); - if ( !isOpen() ) - return idx; - TQSqlQuery i = createQuery(); - TQString stmt; - - switch( pro ) { - case TQPSTQLDriver::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 TQPSTQLDriver::Version7: - case TQPSTQLDriver::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 TQPSTQLDriver::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(), qDecodePSTQLType( i.value(1).toInt() ) ); - idx.append( f ); - idx.setName( i.value(2).toString() ); - } - return idx; -} - -TQSqlRecord TQPSTQLDriver::record( const TQString& tablename ) const -{ - TQSqlRecord fil; - if ( !isOpen() ) - return fil; - TQString stmt; - switch( pro ) { - case TQPSTQLDriver::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 TQPSTQLDriver::Version7: - case TQPSTQLDriver::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 TQPSTQLDriver::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(), qDecodePSTQLType( fi.value(1).toInt() ) ); - fil.append( f ); - } - return fil; -} - -TQSqlRecord TQPSTQLDriver::record( const TQSqlQuery& query ) const -{ - TQSqlRecord fil; - if ( !isOpen() ) - return fil; - if ( query.isActive() && query.driver() == this ) { - TQPSTQLResult* result = (TQPSTQLResult*)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 = qDecodePSTQLType( PQftype( result->d->result, i ) ); - TQSqlField rf( name, type ); - fil.append( rf ); - } - } - return fil; -} - -TQSqlRecordInfo TQPSTQLDriver::recordInfo( const TQString& tablename ) const -{ - TQSqlRecordInfo info; - if ( !isOpen() ) - return info; - - TQString stmt; - switch( pro ) { - case TQPSTQLDriver::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 TQPSTQLDriver::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 TQPSTQLDriver::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 TQPSTQLDriver::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 >= TQPSTQLDriver::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(), - qDecodePSTQLType( 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(), - qDecodePSTQLType( query.value( 1 ).toInt() ), - query.value( 2 ).toBool(), - len, - precision, - defVal, - query.value( 1 ).toInt() ) ); - } - } - - return info; -} - -TQSqlRecordInfo TQPSTQLDriver::recordInfo( const TQSqlQuery& query ) const -{ - TQSqlRecordInfo info; - if ( !isOpen() ) - return info; - if ( query.isActive() && query.driver() == this ) { - TQPSTQLResult* result = (TQPSTQLResult*)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, - qDecodePSTQLType( PQftype( result->d->result, i ) ), - -1, - len, - precision, - TQVariant(), - PQftype( result->d->result, i ) ) ); - } - } - return info; -} - -TQString TQPSTQLDriver::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; -} |