📄 qsql_psql.cpp
字号:
PGconn* QPSQLDriver::connection(){ return d->connection;}bool QPSQLDriver::hasFeature( DriverFeature f ) const{ switch ( f ) { case Transactions: return TRUE; case QuerySize: return TRUE; case BLOB: return FALSE; case Unicode: return d->isUtf8; default: return FALSE; }}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; } if ( vMaj == 7 ) { if ( vMin < 1 ) { return QPSQLDriver::Version7; } else { return QPSQLDriver::Version71; } } if ( vMaj > 7 ) { return QPSQLDriver::Version71; } } } else {#ifdef QT_CHECK_RANGE qWarning( "This version of PostgreSQL is not supported and may not work." );#endif } return QPSQLDriver::Version6;}bool QPSQLDriver::open( const QString & db, const QString & user, const QString & password, const QString & host, int port ){ int status; if ( isOpen() ) close(); QString 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( QString::number( port ) ); d->connection = PQconnectdb( connectString.local8Bit().data() ); if ( PQstatus( d->connection ) == CONNECTION_BAD ) { setLastError( qMakeError("Unable to connect", QSqlError::Connection, d ) ); setOpenError( TRUE ); return FALSE; }// Unicode support is only working if the client library has been compiled with// multibyte support.#ifdef MULTIBYTE status = PQsetClientEncoding( d->connection, "UNICODE" ); if ( status == 0 ) { d->isUtf8 = TRUE; }#endif pro = getPSQLVersion( d->connection ); PGresult* dateResult = 0; switch( pro ) { case QPSQLDriver::Version6: dateResult = PQexec( d->connection, "SET DATESTYLE TO 'ISO'" ); break; case QPSQLDriver::Version7: case QPSQLDriver::Version71: dateResult = PQexec( d->connection, "SET DATESTYLE=ISO" ); break; }#ifdef QT_CHECK_RANGE status = PQresultStatus( dateResult ); if ( status != PGRES_COMMAND_OK ) qWarning( PQerrorMessage( d->connection ) );#endif setOpen( TRUE ); return TRUE;}void QPSQLDriver::close(){ if ( isOpen() ) { PQfinish( d->connection ); d->connection = 0; setOpen( FALSE ); setOpenError( FALSE ); }}QSqlQuery QPSQLDriver::createQuery() const{ return QSqlQuery( new QPSQLResult( this, d ) );}bool QPSQLDriver::beginTransaction(){ if ( !isOpen() ) {#ifdef QT_CHECK_RANGE qWarning( "QPSQLDriver::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", QSqlError::Transaction, d ) ); return FALSE; } PQclear( res ); return TRUE;}bool QPSQLDriver::commitTransaction(){ if ( !isOpen() ) {#ifdef QT_CHECK_RANGE qWarning( "QPSQLDriver::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", QSqlError::Transaction, d ) ); return FALSE; } PQclear( res ); return TRUE;}bool QPSQLDriver::rollbackTransaction(){ if ( !isOpen() ) {#ifdef QT_CHECK_RANGE qWarning( "QPSQLDriver::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", QSqlError::Transaction, d ) ); PQclear( res ); return FALSE; } PQclear( res ); return TRUE;}QStringList QPSQLDriver::tables( const QString& /* user */ ) const{ QStringList tl; if ( !isOpen() ) return tl; QSqlQuery t = createQuery(); QString stmt; stmt = "select relname from pg_class where ( relkind = 'r' or relkind = 'v' ) " "and ( relname !~ '^Inv' ) " "and ( relname !~ '^pg_' ) "; t.exec( stmt ); while ( t.isActive() && t.next() ) tl.append( t.value(0).toString() ); return tl;}QSqlIndex QPSQLDriver::primaryIndex( const QString& tablename ) const{ QSqlIndex idx( tablename ); if ( !isOpen() ) return idx; QSqlQuery i = createQuery(); QString stmt; switch( pro ) { case QPSQLDriver::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 pg_cl.relname = '%1_pkey' 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"; break; case QPSQLDriver::Version7: case QPSQLDriver::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 pg_cl.relname = '%1_pkey' 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"; break; } i.exec( stmt.arg( tablename ) ); while ( i.isActive() && i.next() ) { QSqlField f( i.value(0).toString(), qDecodePSQLType( i.value(1).toInt() ) ); idx.append( f ); idx.setName( i.value(2).toString() ); } return idx;}QSqlRecord QPSQLDriver::record( const QString& tablename ) const{ QSqlRecord fil; if ( !isOpen() ) return fil; QString stmt; switch( pro ) { case QPSQLDriver::Version6: stmt = "select pg_attribute.attname, int(pg_attribute.atttypid) " "from pg_class, pg_attribute " "where pg_class.relname = '%1' " "and pg_attribute.attnum > 0 " "and pg_attribute.attrelid = pg_class.oid "; break; case QPSQLDriver::Version7: case QPSQLDriver::Version71: stmt = "select pg_attribute.attname, pg_attribute.atttypid::int " "from pg_class, pg_attribute " "where pg_class.relname = '%1' " "and pg_attribute.attnum > 0 " "and pg_attribute.attrelid = pg_class.oid "; break; } QSqlQuery fi = createQuery(); fi.exec( stmt.arg( tablename ) ); while ( fi.next() ) { QSqlField f( fi.value(0).toString(), qDecodePSQLType( fi.value(1).toInt() ) ); fil.append( f ); } return fil;}QSqlRecord QPSQLDriver::record( const QSqlQuery& query ) const{ QSqlRecord fil; if ( !isOpen() ) return fil; if ( query.isActive() && query.driver() == this ) { QPSQLResult* result = (QPSQLResult*)query.result(); int count = PQnfields( result->d->result ); for ( int i = 0; i < count; ++i ) { QString name = PQfname( result->d->result, i ); QVariant::Type type = qDecodePSQLType( PQftype( result->d->result, i ) ); QSqlField rf( name, type ); fil.append( rf ); } } return fil;}QSqlRecordInfo QPSQLDriver::recordInfo( const QString& tablename ) const{ QSqlRecordInfo info; if ( !isOpen() ) return info; QString stmt; switch( pro ) { case QPSQLDriver::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 pg_class.relname = '%1' " "and pg_attribute.attnum > 0 " "and pg_attribute.attrelid = pg_class.oid "; break; case QPSQLDriver::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 pg_class.relname = '%1' " "and pg_attribute.attnum > 0 " "and pg_attribute.attrelid = pg_class.oid "; break; case QPSQLDriver::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 pg_class.relname = '%1' " "and pg_attribute.attnum > 0 " "and pg_attribute.attrelid = pg_class.oid "; break; } QSqlQuery query = createQuery(); query.exec( stmt.arg( tablename ) ); if ( pro == QPSQLDriver::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; } QString defVal = query.value( 5 ).toString(); if ( !defVal.isEmpty() && defVal.startsWith( "'" ) ) defVal = defVal.mid( 1, defVal.length() - 2 ); info.append( QSqlFieldInfo( 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() ) { QString defVal; QString stmt2 = "select pg_attrdef.adsrc from pg_attrdef where " "pg_attrdef.adrelid = %1 and pg_attrdef.adnum = %2 "; QSqlQuery 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( QSqlFieldInfo( query.value( 0 ).toString(), qDecodePSQLType( query.value( 1 ).toInt() ), query.value( 2 ).toBool(), len, precision, defVal, query.value( 1 ).toInt() ) ); } } return info;}QSqlRecordInfo QPSQLDriver::recordInfo( const QSqlQuery& query ) const{ QSqlRecordInfo info; if ( !isOpen() ) return info; if ( query.isActive() && query.driver() == this ) { QPSQLResult* result = (QPSQLResult*)query.result(); int count = PQnfields( result->d->result ); for ( int i = 0; i < count; ++i ) { QString 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( QSqlFieldInfo( name, qDecodePSQLType( PQftype( result->d->result, i ) ), -1, len, precision, QVariant(), PQftype( result->d->result, i ) ) ); } } return info;}QString QPSQLDriver::formatValue( const QSqlField* field, bool ) const{ QString r; if ( field->isNull() ) { r = nullText(); } else { switch ( field->type() ) { case QVariant::DateTime: if ( field->value().toDateTime().isValid() ) { QDate dt = field->value().toDateTime().date(); QTime tm = field->value().toDateTime().time(); // msecs need to be right aligned otherwise psql // interpretes them wrong r = "'" + QString::number( dt.year() ) + "-" + QString::number( dt.month() ) + "-" + QString::number( dt.day() ) + " " + tm.toString() + "." + QString::number( tm.msec() ).rightJustify( 3, '0' ) + "'"; } else { r = nullText(); } break; case QVariant::Time: if ( field->value().toTime().isValid() ) { r = field->value().toTime().toString( Qt::ISODate ); } else { r = nullText(); } case QVariant::String: case QVariant::CString: { // Escape '\' characters r = QSqlDriver::formatValue( field ); r.replace( "\\", "\\\\" ); break; } case QVariant::Bool: if ( field->value().toBool() ) r = "TRUE"; else r = "FALSE"; break; case QVariant::ByteArray:#ifdef QT_CHECKRANGE // bytearrays cannot be inserted directly into postgresql qWarning( "QPSQLDriver::formatValue: cannot format ByteArray." );#endif break; case QVariant::Rect: { QRect rec = field->value().toRect(); // upper right corner then lower left according to psql docs r = "'(" + QString::number( rec.right() ) + "," + QString::number( rec.bottom() ) + "),(" + QString::number( rec.left() ) + "," + QString::number( rec.top() ) + ")'"; break; } case QVariant::Point: { QPoint p = field->value().toPoint(); r = "'(" + QString::number( p.x() ) + "," + QString::number( p.y() ) + ")'"; break; } case QVariant::PointArray: { QPointArray pa = field->value().toPointArray(); r = "' "; for ( int i = 0; i < (int)pa.size(); ++i ) { r += "(" + QString::number( pa[i].x() ) + "," + QString::number( pa[i].y() ) + "),"; } r.truncate( r.length() - 1 ); r += "'"; break; } default: r = QSqlDriver::formatValue( field ); break; } } return r;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -