📄 qsql_odbc.cpp
字号:
setOpenError( TRUE ); return FALSE; } QString connQStr; // support the "DRIVER={SQL SERVER};SERVER=blah;" syntax// QRegExp cr( "DRIVER\\s*=\\s*\\{.+\\}\\s*;\\s*SERVER\\s*=\\s*.+;" ); if ( db.contains(".dsn") ) { connQStr = "FILEDSN=" + db; } else if ( db.startsWith( "DRIVER" ) && db.contains( "SERVER" ) ) { connQStr = db; } else { connQStr = "DSN=" + db; } connQStr += ";UID=" + user + ";PWD=" + password + ";"; SQLSMALLINT cb; SQLTCHAR connOut[1024]; r = SQLDriverConnect( d->hDbc, NULL,#ifdef UNICODE (SQLWCHAR*)connQStr.unicode(),#else (SQLCHAR*)connQStr.latin1(),#endif (SQLSMALLINT)connQStr.length(), connOut, 1024, &cb, SQL_DRIVER_NOPROMPT); if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) { setLastError( qMakeError( "Unable to connect", QSqlError::Connection, d ) ); setOpenError( TRUE ); return FALSE; } if ( !d->checkDriver() ) { setLastError( qMakeError( "Unable to connect - Driver doesn't support all needed functionality", QSqlError::Connection, d ) ); setOpenError( TRUE ); return FALSE; } d->checkUnicode(); setOpen( TRUE ); return TRUE;}void QODBCDriver::close(){ cleanup(); setOpen( FALSE ); setOpenError( FALSE );}void QODBCDriver::cleanup(){ SQLRETURN r; if ( (isOpen() || isOpenError()) && (d != 0)) { if( d->hDbc ) { // Open statements/descriptors handles are automatically cleaned up by SQLDisconnect r = SQLDisconnect( d->hDbc );#ifdef QT_CHECK_RANGE if ( r != SQL_SUCCESS ) qSqlWarning( "QODBCDriver::disconnect: Unable to disconnect datasource", d );#endif r = SQLFreeHandle( SQL_HANDLE_DBC, d->hDbc );#ifdef QT_CHECK_RANGE if ( r != SQL_SUCCESS ) qSqlWarning( "QODBCDriver::cleanup: Unable to free connection handle", d );#endif d->hDbc = 0; } if ( d->hEnv ) { r = SQLFreeHandle( SQL_HANDLE_ENV, d->hEnv );#ifdef QT_CHECK_RANGE if ( r != SQL_SUCCESS ) qSqlWarning( "QODBCDriver::cleanup: Unable to free environment handle", d );#endif d->hEnv = 0; } }}// checks whether the server can return char, varchar and longvarchar// as two byte unicode charactersvoid QODBCPrivate::checkUnicode(){#if defined(Q_WS_WIN) if ( !qt_winunicode ) { unicode = FALSE; return; }#endif SQLRETURN r; SQLUINTEGER fFunc; unicode = TRUE; r = SQLGetInfo( hDbc, SQL_CONVERT_CHAR, (SQLPOINTER)&fFunc, sizeof(fFunc), NULL ); if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( fFunc & SQL_CVT_WCHAR ) ) { sql_char_type = QVariant::String; } else { unicode = FALSE; } r = SQLGetInfo( hDbc, SQL_CONVERT_VARCHAR, (SQLPOINTER)&fFunc, sizeof(fFunc), NULL ); if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( fFunc & SQL_CVT_WVARCHAR ) ) { sql_varchar_type = QVariant::String; } else { unicode = FALSE; } r = SQLGetInfo( hDbc, SQL_CONVERT_LONGVARCHAR, (SQLPOINTER)&fFunc, sizeof(fFunc), NULL ); if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( fFunc & SQL_CVT_WLONGVARCHAR ) ) { sql_longvarchar_type = QVariant::String; } else { unicode = FALSE; }}bool QODBCPrivate::checkDriver() const{#ifdef ODBC_CHECK_DRIVER // do not query for SQL_API_SQLFETCHSCROLL because it can't be used at this time static const SQLUSMALLINT reqFunc[] = { SQL_API_SQLDESCRIBECOL, SQL_API_SQLGETDATA, SQL_API_SQLCOLUMNS, SQL_API_SQLGETSTMTATTR, SQL_API_SQLGETDIAGREC, SQL_API_SQLEXECDIRECT, SQL_API_SQLGETINFO, SQL_API_SQLTABLES, 0 }; // these functions are optional static const SQLUSMALLINT optFunc[] = { SQL_API_SQLNUMRESULTCOLS, SQL_API_SQLROWCOUNT, 0 }; SQLRETURN r; SQLUSMALLINT sup; int i; // check the required functions for ( i = 0; reqFunc[ i ] != 0; ++i ) { r = SQLGetFunctions( hDbc, reqFunc[ i ], &sup );#ifdef QT_CHECK_RANGE if ( r != SQL_SUCCESS ) { qSqlWarning( "QODBCDriver::checkDriver: Cannot get list of supported functions", this ); return FALSE; }#endif if ( sup == SQL_FALSE ) {#ifdef QT_CHECK_RANGE qWarning ( "QODBCDriver::open: Warning - Driver doesn't support all needed functionality (%d). " "Please look at the Qt SQL Module Driver documentation for more information.", reqFunc[ i ] );#endif return FALSE; } } // these functions are optional and just generate a warning for ( i = 0; optFunc[ i ] != 0; ++i ) { r = SQLGetFunctions( hDbc, optFunc[ i ], &sup );#ifdef QT_CHECK_RANGE if ( r != SQL_SUCCESS ) { qSqlWarning( "QODBCDriver::checkDriver: Cannot get list of supported functions", this ); return FALSE; }#endif if ( sup == SQL_FALSE ) {#ifdef QT_CHECK_RANGE qWarning( "QODBCDriver::checkDriver: Warning - Driver doesn't support some non-critical functions (%d)", optFunc[ i ] );#endif return TRUE; } }#endif //ODBC_CHECK_DRIVER return TRUE;}QSqlQuery QODBCDriver::createQuery() const{ return QSqlQuery( new QODBCResult( this, d ) );}bool QODBCDriver::beginTransaction(){ if ( !isOpen() ) {#ifdef QT_CHECK_RANGE qWarning(" QODBCDriver::beginTransaction: Database not open" );#endif return FALSE; } SQLUINTEGER ac(SQL_AUTOCOMMIT_OFF); SQLRETURN r = SQLSetConnectAttr( d->hDbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)ac, sizeof(ac)); if ( r != SQL_SUCCESS ) { setLastError( qMakeError( "Unable to disable autocommit", QSqlError::Transaction, d ) ); return FALSE; } return TRUE;}bool QODBCDriver::commitTransaction(){ if ( !isOpen() ) {#ifdef QT_CHECK_RANGE qWarning(" QODBCDriver::commitTransaction: Database not open" );#endif return FALSE; } SQLRETURN r = SQLEndTran( SQL_HANDLE_ENV, d->hEnv, SQL_COMMIT); if ( r != SQL_SUCCESS ) { setLastError( qMakeError("Unable to commit transaction", QSqlError::Transaction, d ) ); return FALSE; } return endTrans();}bool QODBCDriver::rollbackTransaction(){ if ( !isOpen() ) {#ifdef QT_CHECK_RANGE qWarning(" QODBCDriver::rollbackTransaction: Database not open" );#endif return FALSE; } SQLRETURN r = SQLEndTran( SQL_HANDLE_ENV, d->hEnv, SQL_ROLLBACK); if ( r != SQL_SUCCESS ) { setLastError( qMakeError( "Unable to rollback transaction", QSqlError::Transaction, d ) ); return FALSE; } return endTrans();}bool QODBCDriver::endTrans(){ SQLUINTEGER ac(SQL_AUTOCOMMIT_ON); SQLRETURN r = SQLSetConnectAttr( d->hDbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)ac, sizeof(ac)); if ( r != SQL_SUCCESS ) { setLastError( qMakeError( "Unable to enable autocommit", QSqlError::Transaction, d ) ); return FALSE; } return TRUE;}QStringList QODBCDriver::tables( const QString& /* user */ ) const{ QStringList tl; if ( !isOpen() ) return tl; SQLHANDLE hStmt; SQLRETURN r = SQLAllocHandle( SQL_HANDLE_STMT, d->hDbc, &hStmt ); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "QODBCDriver::tables: Unable to allocate handle", d );#endif return tl; } r = SQLSetStmtAttr( hStmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, SQL_IS_UINTEGER ); // Prevent SQLTables to display all the system tables QString tableType = "TABLE"; r = SQLTables( hStmt, NULL, 0, NULL, 0, NULL, 0,#ifdef UNICODE (SQLWCHAR*)tableType.unicode(),#else (SQLCHAR*)tableType.latin1(),#endif tableType.length() /* characters, not bytes */ );#ifdef QT_CHECK_RANGE if ( r != SQL_SUCCESS ) qSqlWarning( "QODBCDriver::tables Unable to execute table list", d );#endif r = SQLFetchScroll( hStmt, SQL_FETCH_NEXT, 0); while ( r == SQL_SUCCESS ) { bool isNull; QString fieldVal = qGetStringData( hStmt, 2, -1, isNull, d->unicode ); tl.append( fieldVal ); r = SQLFetchScroll( hStmt, SQL_FETCH_NEXT, 0); } r = SQLFreeHandle( SQL_HANDLE_STMT, hStmt ); if ( r!= SQL_SUCCESS ) qSqlWarning( "QODBCDriver: Unable to free statement handle" + QString::number(r), d ); return tl;}QSqlIndex QODBCDriver::primaryIndex( const QString& tablename ) const{ QSqlIndex index( tablename ); if ( !isOpen() ) return index; bool usingSpecialColumns = FALSE; QSqlRecord rec = record( tablename ); SQLHANDLE hStmt; SQLRETURN r = SQLAllocHandle( SQL_HANDLE_STMT, d->hDbc, &hStmt ); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "QODBCDriver::primaryIndex: Unable to list primary key", d );#endif return index; } QString catalog, schema, table; qSplitTableQualifier( tablename, &catalog, &schema, &table ); r = SQLSetStmtAttr( hStmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, SQL_IS_UINTEGER ); r = SQLPrimaryKeys( hStmt,#ifdef UNICODE catalog.length() == 0 ? NULL : (SQLWCHAR*)catalog.unicode(),#else catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.latin1(),#endif catalog.length(),#ifdef UNICODE schema.length() == 0 ? NULL : (SQLWCHAR*)schema.unicode(),#else schema.length() == 0 ? NULL : (SQLCHAR*)schema.latin1(),#endif schema.length(),#ifdef UNICODE (SQLWCHAR*)table.unicode(),#else (SQLCHAR*)table.latin1(),#endif table.length() /* in characters, not in bytes */); // if the SQLPrimaryKeys() call does not succeed (e.g the driver // does not support it) - try an alternative method to get hold of // the primary index (e.g MS Access and FoxPro) if ( r != SQL_SUCCESS ) { r = SQLSpecialColumns( hStmt, SQL_BEST_ROWID,#ifdef UNICODE catalog.length() == 0 ? NULL : (SQLWCHAR*)catalog.unicode(),#else catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.latin1(),#endif catalog.length(),#ifdef UNICODE schema.length() == 0 ? NULL : (SQLWCHAR*)schema.unicode(),#else schema.length() == 0 ? NULL : (SQLCHAR*)schema.latin1(),#endif schema.length(),#ifdef UNICODE (SQLWCHAR*)table.unicode(),#else (SQLCHAR*)table.latin1(),#endif table.length(), SQL_SCOPE_CURROW, SQL_NULLABLE ); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "QODBCDriver::primaryIndex: Unable to execute primary key list", d );#endif } else { usingSpecialColumns = TRUE; } } r = SQLFetchScroll( hStmt, SQL_FETCH_NEXT, 0 ); bool isNull; int fakeId = 0; QString cName, idxName; // Store all fields in a StringList because some drivers can't detail fields in this FETCH loop while ( r == SQL_SUCCESS ) { if ( usingSpecialColumns ) { cName = qGetStringData( hStmt, 1, -1, isNull, d->unicode ); // column name idxName = QString::number( fakeId++ ); // invent a fake index name } else { cName = qGetStringData( hStmt, 3, -1, isNull, d->unicode ); // column name idxName = qGetStringData( hStmt, 5, -1, isNull, d->unicode ); // pk index name } index.append( *(rec.field( cName )) ); index.setName( idxName ); r = SQLFetchScroll( hStmt, SQL_FETCH_NEXT, 0 ); } r = SQLFreeHandle( SQL_HANDLE_STMT, hStmt ); if ( r!= SQL_SUCCESS ) qSqlWarning( "QODBCDriver: Unable to free statement handle" + QString::number(r), d ); return index;}QSqlRecord QODBCDriver::record( const QString& tablename ) const{ return recordInfo( tablename ).toRecord();}QSqlRecord QODBCDriver::record( const QSqlQuery& query ) const{ return recordInfo( query ).toRecord();}QSqlRecordInfo QODBCDriver::recordInfo( const QString& tablename ) const{ QSqlRecordInfo fil; if ( !isOpen() ) return fil; SQLHANDLE hStmt; QString catalog, schema, table; qSplitTableQualifier( tablename, &catalog, &schema, &table ); SQLRETURN r = SQLAllocHandle( SQL_HANDLE_STMT, d->hDbc, &hStmt ); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "QODBCDriver::record: Unable to allocate handle", d );#endif return fil; } r = SQLSetStmtAttr( hStmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, SQL_IS_UINTEGER ); r = SQLColumns( hStmt,#ifdef UNICODE catalog.length() == 0 ? NULL : (SQLWCHAR*)catalog.unicode(),#else catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.latin1(),#endif catalog.length(),#ifdef UNICODE schema.length() == 0 ? NULL : (SQLWCHAR*)schema.unicode(),#else schema.length() == 0 ? NULL : (SQLCHAR*)schema.latin1(),#endif schema.length(),#ifdef UNICODE (SQLWCHAR*)table.unicode(),#else (SQLCHAR*)table.latin1(),#endif table.length(), NULL, 0 );#ifdef QT_CHECK_RANGE if ( r != SQL_SUCCESS ) qSqlWarning( "QODBCDriver::record: Unable to execute column list", d );#endif r = SQLFetchScroll( hStmt, SQL_FETCH_NEXT, 0); // Store all fields in a StringList because some drivers can't detail fields in this FETCH loop while ( r == SQL_SUCCESS ) { fil.append( qMakeFieldInfo( hStmt, d ) ); r = SQLFetchScroll( hStmt, SQL_FETCH_NEXT, 0); } r = SQLFreeHandle( SQL_HANDLE_STMT, hStmt ); if ( r!= SQL_SUCCESS ) qSqlWarning( "QODBCDriver: Unable to free statement handle " + QString::number(r), d ); return fil;}QSqlRecordInfo QODBCDriver::recordInfo( const QSqlQuery& query ) const{ QSqlRecordInfo fil; if ( !isOpen() ) return fil; if ( query.isActive() && query.driver() == this ) { QODBCResult* result = (QODBCResult*)query.result(); fil = result->d->rInf; } return fil;}SQLHANDLE QODBCDriver::environment(){ return d->hEnv;}SQLHANDLE QODBCDriver::connection(){ return d->hDbc;}QString QODBCDriver::formatValue( const QSqlField* field, bool trimStrings ) const{ QString r; if ( field->isNull() ) { r = nullText(); } else if ( field->type() == QVariant::DateTime ) { // Use an escape sequence for the datetime fields if ( field->value().toDateTime().isValid() ){ QDate dt = field->value().toDateTime().date(); QTime tm = field->value().toDateTime().time(); // Dateformat has to be "yyyy-MM-dd hh:mm:ss", with leading zeroes if month or day < 10 r = "{ ts '" + QString::number(dt.year()) + "-" + QString::number(dt.month()).rightJustify( 2, '0', TRUE ) + "-" + QString::number(dt.day()).rightJustify( 2, '0', TRUE ) + " " + tm.toString() + "' }"; } else r = nullText(); } else if ( field->type() == QVariant::ByteArray ) { QByteArray ba = field->value().toByteArray(); QString res; static const char hexchars[] = "0123456789abcdef"; for ( uint i = 0; i < ba.size(); ++i ) { uchar s = (uchar) ba[(int)i]; res += hexchars[s >> 4]; res += hexchars[s & 0x0f]; } r = "0x" + res; } else { r = QSqlDriver::formatValue( field, trimStrings ); } return r;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -