📄 qsql_odbc.cpp
字号:
bool QODBCResult::fetchNext(){ SQLRETURN r; fieldCache.clear(); nullCache.clear(); r = SQLFetchScroll( d->hStmt, SQL_FETCH_NEXT, 0 ); if ( r != SQL_SUCCESS ) return FALSE; setAt( at() + 1 ); return TRUE;}bool QODBCResult::fetchFirst(){ if ( isForwardOnly() && at() != QSql::BeforeFirst ) return FALSE; SQLRETURN r; fieldCache.clear(); nullCache.clear(); if ( isForwardOnly() ) { return fetchNext(); } r = SQLFetchScroll( d->hStmt, SQL_FETCH_FIRST, 0 ); if ( r != SQL_SUCCESS ) return FALSE; setAt( 0 ); return TRUE;}bool QODBCResult::fetchPrior(){ if ( isForwardOnly() ) return FALSE; SQLRETURN r; fieldCache.clear(); nullCache.clear(); r = SQLFetchScroll( d->hStmt, SQL_FETCH_PRIOR, 0 ); if ( r != SQL_SUCCESS ) return FALSE; setAt( at() - 1 ); return TRUE;}bool QODBCResult::fetchLast(){ SQLRETURN r; fieldCache.clear(); nullCache.clear(); if ( isForwardOnly() ) { // cannot seek to last row in forwardOnly mode, so we have to use brute force int i = at(); while ( fetchNext() ) ++i; setAt( i ); return TRUE; } r = SQLFetchScroll( d->hStmt, SQL_FETCH_LAST, 0 ); if ( r != SQL_SUCCESS ) { return FALSE; } SQLINTEGER currRow; r = SQLGetStmtAttr( d->hStmt, SQL_ROW_NUMBER, &currRow, SQL_IS_INTEGER, 0 ); if ( r != SQL_SUCCESS ) return FALSE; setAt( currRow-1 ); return TRUE;}QVariant QODBCResult::data( int field ){ if ( fieldCache.contains( field ) ) return fieldCache[ field ]; SQLRETURN r(0); SQLINTEGER lengthIndicator = 0; bool isNull = FALSE; int current = fieldCache.count(); for ( ; current < (field + 1); ++current ) { const QSqlFieldInfo info = d->rInf[ current ]; switch ( info.type() ) { case QVariant::Int: isNull = FALSE; fieldCache[ current ] = QVariant( qGetIntData( d->hStmt, current, isNull ) ); nullCache[ current ] = isNull; break; case QVariant::Date: DATE_STRUCT dbuf; r = SQLGetData( d->hStmt, current+1, SQL_C_DATE, (SQLPOINTER)&dbuf, 0, &lengthIndicator ); if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( lengthIndicator != SQL_NULL_DATA ) ) { fieldCache[ current ] = QVariant( QDate( dbuf.year, dbuf.month, dbuf.day ) ); nullCache[ current ] = FALSE; } else { fieldCache[ current ] = QVariant( QDate() ); nullCache[ current ] = TRUE; } break; case QVariant::Time: TIME_STRUCT tbuf; r = SQLGetData( d->hStmt, current+1, SQL_C_TIME, (SQLPOINTER)&tbuf, 0, &lengthIndicator ); if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( lengthIndicator != SQL_NULL_DATA ) ) { fieldCache[ current ] = QVariant( QTime( tbuf.hour, tbuf.minute, tbuf.second ) ); nullCache[ current ] = FALSE; } else { fieldCache[ current ] = QVariant( QTime() ); nullCache[ current ] = TRUE; } break; case QVariant::DateTime: TIMESTAMP_STRUCT dtbuf; r = SQLGetData( d->hStmt, current+1, SQL_C_TIMESTAMP, (SQLPOINTER)&dtbuf, 0, &lengthIndicator ); if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( lengthIndicator != SQL_NULL_DATA ) ) { fieldCache[ current ] = QVariant( QDateTime( QDate( dtbuf.year, dtbuf.month, dtbuf.day ), QTime( dtbuf.hour, dtbuf.minute, dtbuf.second ) ) ); nullCache[ current ] = FALSE; } else { fieldCache[ current ] = QVariant( QDateTime() ); nullCache[ current ] = TRUE; } break; case QVariant::ByteArray: { isNull = FALSE; QByteArray val = qGetBinaryData( d->hStmt, current, lengthIndicator, isNull ); fieldCache[ current ] = QVariant( val ); nullCache[ current ] = isNull; break; } case QVariant::String: isNull = FALSE; fieldCache[ current ] = QVariant( qGetStringData( d->hStmt, current, info.length(), isNull, TRUE ) ); nullCache[ current ] = isNull; break; case QVariant::Double: // bind Double values as string to prevent loss of precision isNull = FALSE; // length + 1 for the comma fieldCache[ current ] = QVariant( qGetStringData( d->hStmt, current, info.length() + 1, isNull, FALSE ) ); nullCache[ current ] = isNull; break; case QVariant::CString: default: isNull = FALSE; fieldCache[ current ] = QVariant( qGetStringData( d->hStmt, current, info.length(), isNull, FALSE ) ); nullCache[ current ] = isNull; break; } } return fieldCache[ --current ];}bool QODBCResult::isNull( int field ){ if ( !fieldCache.contains( field ) ) { // since there is no good way to find out whether the value is NULL // without fetching the field we'll fetch it here. // (data() also sets the NULL flag) data( field ); } return nullCache[ field ];}int QODBCResult::size(){ return -1;// int size(-1);// int at(0);// SQLINTEGER currRow(0);// SQLRETURN r = SQLGetStmtAttr( d->hStmt,// SQL_ROW_NUMBER,// &currRow,// SQL_IS_INTEGER,// 0);// at = currRow;// r = SQLFetchScroll( d->hStmt,// SQL_FETCH_LAST,// 0);// if ( r == SQL_SUCCESS ) {// r = SQLGetStmtAttr( d->hStmt,// SQL_ROW_NUMBER,// &currRow,// SQL_IS_INTEGER,// 0);// if ( r == SQL_SUCCESS )// size = currRow;// r = SQLFetchScroll( d->hStmt,// SQL_FETCH_ABSOLUTE,// currRow);// if ( r != SQL_SUCCESS )// qSqlWarning("QODBCResult::size: Unable to restore position", d );// }// return size;}int QODBCResult::numRowsAffected(){ SQLINTEGER affectedRowCount(0); SQLRETURN r = SQLRowCount( d->hStmt, &affectedRowCount); if ( r == SQL_SUCCESS ) return affectedRowCount;#ifdef QT_CHECK_RANGE else qSqlWarning( "QODBCResult::numRowsAffected: Unable to count affected rows", d );#endif return -1;}bool QODBCResult::prepare( const QString& query ){ setActive( FALSE ); setAt( QSql::BeforeFirst ); SQLRETURN r; d->rInf.clear(); // If a statement handle exists - reuse it if ( d->hStmt ) { r = SQLFreeHandle( SQL_HANDLE_STMT, d->hStmt ); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "QODBCResult::prepare: Unable to close statement", d );#endif return FALSE; } } //else { r = SQLAllocHandle( SQL_HANDLE_STMT, d->hDbc, &d->hStmt ); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "QODBCResult::prepare: Unable to allocate statement handle", d );#endif return FALSE; }// } if ( isForwardOnly() ) { r = SQLSetStmtAttr( d->hStmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, SQL_IS_UINTEGER ); } else { r = SQLSetStmtAttr( d->hStmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_STATIC, SQL_IS_UINTEGER ); } if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "QODBCResult::prepare: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration", d );#endif return FALSE; }#ifdef UNICODE r = SQLPrepare( d->hStmt, (SQLWCHAR*) query.unicode(), (SQLINTEGER) query.length() );#else QCString query8 = query.local8Bit(); r = SQLPrepare( d->hStmt, (SQLCHAR*) query8.data(), (SQLINTEGER) query8.length() );#endif if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "QODBCResult::prepare: Unable to prepare statement", d );#endif return FALSE; } return TRUE;}bool QODBCResult::exec(){ SQLRETURN r; QPtrList<QVirtualDestructor> tmpStorage; // holds temporary ptrs. which will be deleted on fu exit tmpStorage.setAutoDelete( TRUE ); // bind parameters - only positional binding allowed if ( extension()->index.count() > 0 ) { QMap<int, QString>::Iterator it; int para = 1; QVariant val; for ( it = extension()->index.begin(); it != extension()->index.end(); ++it ) { val = extension()->values[ it.data() ].value; SQLINTEGER * ind = new SQLINTEGER( SQL_NTS ); tmpStorage.append( qAutoDeleter(ind) ); if ( val.isNull() ) { *ind = SQL_NULL_DATA; } switch ( val.type() ) { case QVariant::Date: { DATE_STRUCT * dt = new DATE_STRUCT; tmpStorage.append( qAutoDeleter(dt) ); QDate qdt = val.toDate(); dt->year = qdt.year(); dt->month = qdt.month(); dt->day = qdt.day(); r = SQLBindParameter( d->hStmt, para, SQL_PARAM_INPUT, SQL_C_DATE, SQL_DATE, 0, 0, (void *) dt, 0, *ind == SQL_NULL_DATA ? ind : NULL ); break; } case QVariant::Time: { TIME_STRUCT * dt = new TIME_STRUCT; tmpStorage.append( qAutoDeleter(dt) ); QTime qdt = val.toTime(); dt->hour = qdt.hour(); dt->minute = qdt.minute(); dt->second = qdt.second(); r = SQLBindParameter( d->hStmt, para, SQL_PARAM_INPUT, SQL_C_TIME, SQL_TIME, 0, 0, (void *) dt, 0, *ind == SQL_NULL_DATA ? ind : NULL ); break; } case QVariant::DateTime: { TIMESTAMP_STRUCT * dt = new TIMESTAMP_STRUCT; tmpStorage.append( qAutoDeleter(dt) ); QDateTime qdt = val.toDateTime(); dt->year = qdt.date().year(); dt->month = qdt.date().month(); dt->day = qdt.date().day(); dt->hour = qdt.time().hour(); dt->minute = qdt.time().minute(); dt->second = qdt.time().second(); dt->fraction = 0; r = SQLBindParameter( d->hStmt, para, SQL_PARAM_INPUT, SQL_C_TIMESTAMP, SQL_TIMESTAMP, 0, 0, (void *) dt, 0, *ind == SQL_NULL_DATA ? ind : NULL ); break; } case QVariant::Int: { int * v = new int( val.toInt() ); tmpStorage.append( qAutoDeleter(v) ); r = SQLBindParameter( d->hStmt, para, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, (void *) v, 0, *ind == SQL_NULL_DATA ? ind : NULL ); break; } case QVariant::Double: { double * v = new double( val.toDouble() ); tmpStorage.append( qAutoDeleter(v) ); r = SQLBindParameter( d->hStmt, para, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, (void *) v, 0, *ind == SQL_NULL_DATA ? ind : NULL ); break; } case QVariant::ByteArray: { QByteArray ba = val.toByteArray(); if ( *ind != SQL_NULL_DATA ) { *ind = ba.size(); } r = SQLBindParameter( d->hStmt, para, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, ba.size(), 0, (void *) ba.data(), ba.size(), ind ); break; } case QVariant::String: if ( d->unicode ) { QString * str = new QString( val.asString() ); str->ucs2(); int len = str->length()*2; tmpStorage.append( qAutoDeleter(str) ); r = SQLBindParameter( d->hStmt, para, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WVARCHAR, str->length(), 0, (void *) str->unicode(), len, ind ); break; } // fall through default: { QCString * str = new QCString( val.asString().local8Bit() ); tmpStorage.append( qAutoDeleter(str) ); r = SQLBindParameter( d->hStmt, para, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, str->length() + 1, 0, (void *) str->data(), str->length() + 1, ind ); break; } } para++; if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qWarning( "QODBCResult::exec: unable to bind variable: " + qODBCWarn( d ) );#endif setLastError( qMakeError( "Unable to bind variable", QSqlError::Statement, d ) ); return FALSE; } } } r = SQLExecute( d->hStmt ); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qWarning( "QODBCResult::exec: Unable to execute statement: " + qODBCWarn( d ) );#endif setLastError( qMakeError( "Unable to execute statement", QSqlError::Statement, d ) ); return FALSE; } SQLSMALLINT count; r = SQLNumResultCols( d->hStmt, &count ); if ( count ) { setSelect( TRUE ); for ( int i = 0; i < count; ++i ) { d->rInf.append( qMakeFieldInfo( d, i ) ); } } else { setSelect( FALSE ); } setActive( TRUE ); return TRUE;}////////////////////////////////////////QODBCDriver::QODBCDriver( QObject * parent, const char * name ): QSqlDriver(parent,name ? name : "QODBC"){ init();}void QODBCDriver::init(){ d = new QODBCPrivate();}QODBCDriver::~QODBCDriver(){ cleanup(); delete d;}bool QODBCDriver::hasFeature( DriverFeature f ) const{ switch ( f ) { case Transactions: { if ( !d->hDbc ) return FALSE; SQLUSMALLINT txn; SQLSMALLINT t; int r = SQLGetInfo( d->hDbc, (SQLUSMALLINT)SQL_TXN_CAPABLE, &txn, sizeof(txn), &t); if ( r != SQL_SUCCESS || txn == SQL_TC_NONE ) return FALSE; else return TRUE; } case QuerySize: return FALSE; case BLOB: return TRUE; case Unicode: return d->unicode; case PreparedQueries: return TRUE; case PositionalPlaceholders: return TRUE; default: return FALSE; }}bool QODBCDriver::open( const QString & db, const QString & user, const QString & password, const QString &, int ){ if ( isOpen() ) close(); SQLRETURN r; r = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &d->hEnv); if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) {#ifdef QT_CHECK_RANGE qSqlWarning( "QODBCDriver::open: Unable to allocate environment", d );#endif setOpenError( TRUE ); return FALSE; } r = SQLSetEnvAttr( d->hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC2, SQL_IS_UINTEGER ); r = SQLAllocHandle(SQL_HANDLE_DBC, d->hEnv, &d->hDbc); if ( r != SQL_SUCCESS ) {#ifdef QT_CHECK_RANGE qSqlWarning( "QODBCDriver::open: Unable to allocate connection", d );#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -