⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qsql_psql.cpp

📁 这个是Linux的qt源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/******************************************************************************** Implementation of PostgreSQL driver classes**** Created : 001103**** Copyright (C) 1992-2002 Trolltech AS.  All rights reserved.**** This file is part of the sql module of the Qt GUI Toolkit.**** This file may be distributed under the terms of the Q Public License** as defined by Trolltech AS of Norway and appearing in the file** LICENSE.QPL included in the packaging of this file.**** This file may be distributed and/or modified under the terms of the** GNU General Public License version 2 as published by the Free Software** Foundation and appearing in the file LICENSE.GPL included in the** packaging of this file.**** Licensees holding valid Qt Enterprise Edition licenses may use this** file in accordance with the Qt Commercial License Agreement provided** with the Software.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.**** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for**   information about Qt Commercial License Agreements.** See http://www.trolltech.com/qpl/ for QPL licensing information.** See http://www.trolltech.com/gpl/ for GPL licensing information.**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.************************************************************************/#include "qsql_psql.h"#include <private/qsqlextension_p.h>#include <math.h>#include <qpointarray.h>#include <qsqlrecord.h>#include <qregexp.h>#include <qdatetime.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 errnoQPtrDict<QSqlDriverExtension> *qSqlDriverExtDict();QPtrDict<QSqlOpenExtension> *qSqlOpenExtDict();class QPSQLPrivate{public:  QPSQLPrivate():connection(0), result(0), isUtf8(FALSE) {}    PGconn	*connection;    PGresult	*result;    bool        isUtf8;};class QPSQLDriverExtension : public QSqlDriverExtension{public:    QPSQLDriverExtension( QPSQLDriver *dri )	: QSqlDriverExtension(), driver(dri) { }    ~QPSQLDriverExtension() {}    bool isOpen() const;private:    QPSQLDriver *driver;};bool QPSQLDriverExtension::isOpen() const{    return PQstatus( driver->connection() ) == CONNECTION_OK;}class QPSQLOpenExtension : public QSqlOpenExtension{public:    QPSQLOpenExtension( QPSQLDriver *dri )	: QSqlOpenExtension(), driver(dri) { }    ~QPSQLOpenExtension() {}    bool open( const QString& db,	       const QString& user,	       const QString& password,	       const QString& host,	       int port,	       const QString& connOpts );private:    QPSQLDriver *driver;};bool QPSQLOpenExtension::open( const QString& db,			       const QString& user,			       const QString& password,			       const QString& host,			       int port,			       const QString& connOpts ){    return driver->open( db, user, password, host, port, connOpts );}static QSqlError qMakeError( const QString& err, int type, const QPSQLPrivate* p ){    return QSqlError("QPSQL: " + err, QString(PQerrorMessage( p->connection )), type);}static QVariant::Type qDecodePSQLType( int t ){    QVariant::Type type = QVariant::Invalid;    switch ( t ) {    case BOOLOID	:	type = QVariant::Bool;	break;    case INT8OID	:	type = QVariant::LongLong;	break;    case INT2OID	:	//    case INT2VECTOROID  : // 7.x    case INT4OID        :	type = QVariant::Int;	break;    case NUMERICOID     :    case FLOAT4OID      :    case FLOAT8OID      :	type = QVariant::Double;	break;    case ABSTIMEOID     :    case RELTIMEOID     :    case DATEOID	:	type = QVariant::Date;	break;    case TIMEOID	:#ifdef TIMETZOID // 7.x	case TIMETZOID  :#endif	type = QVariant::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 = QVariant::DateTime;	break;	//    case ZPBITOID	: // 7.x	//    case VARBITOID	: // 7.x    case OIDOID         :    case BYTEAOID       :	type = QVariant::ByteArray;	break;    case REGPROCOID     :    case TIDOID         :    case XIDOID         :    case CIDOID         :	//    case OIDVECTOROID   : // 7.x    case UNKNOWNOID     :	//    case TINTERVALOID   : // 7.x	type = QVariant::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 = QVariant::String;	break;    }    return type;}QVariant::Type qFieldType( QPSQLPrivate* p, int i ){    QVariant::Type type = qDecodePSQLType( PQftype( p->result, i ) );    return type;}QPSQLResult::QPSQLResult( const QPSQLDriver* db, const QPSQLPrivate* p ): QSqlResult( db ),  currentSize( 0 ){    d =   new QPSQLPrivate();    (*d) = (*p);}QPSQLResult::~QPSQLResult(){    cleanup();    delete d;}PGresult* QPSQLResult::result(){    return d->result;}void QPSQLResult::cleanup(){    if ( d->result )	PQclear( d->result );    d->result = 0;    setAt( -1 );    currentSize = 0;    setActive( FALSE );}bool QPSQLResult::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 QPSQLResult::fetchFirst(){    return fetch( 0 );}bool QPSQLResult::fetchLast(){    return fetch( PQntuples( d->result ) - 1 );}// some Postgres conversionsstatic QPoint pointFromString( const QString& 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 QPoint( x, y ) ;    } else	return QPoint();}QDate qDateFromUInt( uint dt ){    int y,m,d;    QDate::julianToGregorian( dt, y, m, d );    return QDate( y, m, d );}QVariant QPSQLResult::data( int i ){    if ( i >= PQnfields( d->result ) ) {	qWarning( "QPSQLResult::data: column %d out of range", i );	return QVariant();    }    int ptype = PQftype( d->result, i );    QVariant::Type type = qDecodePSQLType( ptype );    const QString val = ( d->isUtf8 && ptype != BYTEAOID ) ? 			QString::fromUtf8( PQgetvalue( d->result, at(), i ) ) :			QString::fromLocal8Bit( PQgetvalue( d->result, at(), i ) );    if ( PQgetisnull( d->result, at(), i ) ) {	QVariant v;	v.cast( type );	return v;    }    switch ( type ) {    case QVariant::Bool:	{	    QVariant b ( (bool)(val == "t"), 0 );	    return ( b );	}    case QVariant::String:	return QVariant( val );    case QVariant::LongLong:	if ( val[0] == '-' )	    return QVariant( val.toLongLong() );	else	    return QVariant( val.toULongLong() );    case QVariant::Int:	return QVariant( val.toInt() );    case QVariant::Double:	if ( ptype == NUMERICOID )	    return QVariant( val );	return QVariant( val.toDouble() );    case QVariant::Date:	if ( val.isEmpty() ) {	    return QVariant( QDate() );	} else {	    return QVariant( QDate::fromString( val, Qt::ISODate ) );	}    case QVariant::Time:	if ( val.isEmpty() )	    return QVariant( QTime() );	if ( val.at( val.length() - 3 ) == '+' )	    // strip the timezone	    return QVariant( QTime::fromString( val.left( val.length() - 3 ), Qt::ISODate ) );	return QVariant( QTime::fromString( val, Qt::ISODate ) );    case QVariant::DateTime: {	if ( val.length() < 10 )	    return QVariant( QDateTime() );	// remove the timezone	QString 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 QVariant( QDateTime() );	else	    return QVariant( QDateTime::fromString( dtval, Qt::ISODate ) );    }    case QVariant::Point:	return QVariant( pointFromString( val ) );    case QVariant::Rect: // format '(x,y),(x',y')'	{	    int pivot = val.find( "),(" );	    if ( pivot != -1 )		return QVariant( QRect( pointFromString( val.mid(pivot+2,val.length()) ), pointFromString( val.mid(0,pivot+1) ) ) );	    return QVariant( QRect() );	}    case QVariant::PointArray: // format '((x,y),(x1,y1),...,(xn,yn))'	{	    QRegExp pointPattern("\\([0-9-]*,[0-9-]*\\)");	    int points = val.contains( pointPattern );	    QPointArray 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, QPoint() );		} else {		    parray.setPoint( i, QPoint() );		    break;		}		idx = end+2;	    }	    return QVariant( parray );	}    case QVariant::ByteArray: {	if ( ptype == BYTEAOID ) {	    uint i = 0;	    int index = 0;	    uint len = val.length();	    static const QChar backslash( '\\' );	    QByteArray 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 QVariant( ba );	}	QByteArray ba;	((QSqlDriver*)driver())->beginTransaction();	Oid oid = val.toInt();	int fd = lo_open( d->connection, oid, INV_READ );#ifdef QT_CHECK_RANGE	if ( fd < 0) {	    qWarning( "QPSQLResult::data: unable to open large object for read" );	    ((QSqlDriver*)driver())->commitTransaction();	    return QVariant( 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 );	    ((QSqlDriver*)driver())->commitTransaction();	    return QVariant( 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) {	    qWarning( "QPSQLResult::data: unable to read large object" );	} else {	    ba.duplicate( buf, size );	}	delete [] buf;	lo_close( d->connection, fd );	((QSqlDriver*)driver())->commitTransaction();	return QVariant( ba );    }    default:    case QVariant::Invalid:#ifdef QT_CHECK_RANGE	qWarning("QPSQLResult::data: unknown data type");#endif	;    }    return QVariant();}bool QPSQLResult::isNull( int field ){    PQgetvalue( d->result, at(), field );    return PQgetisnull( d->result, at(), field );}bool QPSQLResult::reset ( const QString& query ){    cleanup();    if ( !driver() )	return FALSE;    if ( !driver()->isOpen() || driver()->isOpenError() )	return FALSE;    setActive( FALSE );    setAt( QSql::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", QSqlError::Statement, d ) );    return FALSE;}int QPSQLResult::size(){    return currentSize;}int QPSQLResult::numRowsAffected(){    return QString( 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 )        qWarning( "%s", PQerrorMessage( connection ) );#endif    PQclear( result );}static QPSQLDriver::Protocol getPSQLVersion( PGconn* connection ){    PGresult* result = PQexec( connection, "select version()" );    int status =  PQresultStatus( result );    if ( status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK ) {	QString val( PQgetvalue( result, 0, 0 ) );	PQclear( result );	QRegExp 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		qWarning( "This version of PostgreSQL is not supported and may not work." );#endif		return QPSQLDriver::Version6;	    }	    if ( vMaj == 6 ) {		return QPSQLDriver::Version6;	    } else if ( vMaj == 7 ) {		if ( vMin < 1 )		    return QPSQLDriver::Version7;		else if ( vMin < 3 )		    return QPSQLDriver::Version71;	    }	    return QPSQLDriver::Version73;	}    } else {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -