diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2021-09-10 16:12:10 +0200 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2021-09-10 18:53:57 +0200 |
commit | ccea340276609c87384ee7fff4837e48baaba9b5 (patch) | |
tree | 01b9d5b5bf8187262bbcb77c21e810ca18be150c | |
parent | c9517311f4c209f549668867c9b07ffa18246dee (diff) |
Clarify that css::sdbc::XClob::getSubString takes 1-based pos
... and fix connectivity::firebird::Clob::getSubString.
XClob::getSubString is modelled after JDBC counterpart, that also
takes 1-based position argument. This is also described in multiple
places in our code:
- OPreparedStatement::setClob
in connectivity/source/drivers/firebird/PreparedStatement.cxx
- OSingleSelectQueryComposer::setConditionByColumn
in dbaccess/source/core/api/SingleSelectQueryComposer.cxx
- ORowSetValue::getString
in connectivity/source/commontools/FValue.cxx
However in some places 0-based value was used (fixed here).
To clarify, the mention that the pos argument is 1-based is put
to the corresponding IDL file.
Also the code in connectivity::firebird::Clob::getSubString had
multiple issues:
- no checks of arguments;
- possibility to throw "nPosition out of range" when just-read
segment has enough data;
- wrong start position in case when nPosition is not aligned to
segment boundary.
This change fixes these, and simplifies the implementation.
Change-Id: I119a62dd7f02c9569ce36395ed8cc1a98c931fcf
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/121884
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
-rw-r--r-- | connectivity/source/drivers/firebird/Clob.cxx | 60 | ||||
-rw-r--r-- | connectivity/source/drivers/firebird/DatabaseMetaData.cxx | 2 | ||||
-rw-r--r-- | connectivity/source/drivers/firebird/ResultSet.cxx | 2 | ||||
-rw-r--r-- | offapi/com/sun/star/sdbc/XClob.idl | 2 |
4 files changed, 31 insertions, 35 deletions
diff --git a/connectivity/source/drivers/firebird/Clob.cxx b/connectivity/source/drivers/firebird/Clob.cxx index 5825a5f2c871..707020b39bbf 100644 --- a/connectivity/source/drivers/firebird/Clob.cxx +++ b/connectivity/source/drivers/firebird/Clob.cxx @@ -71,55 +71,51 @@ sal_Int64 SAL_CALL Clob::length() OUString SAL_CALL Clob::getSubString(sal_Int64 nPosition, sal_Int32 nLength) { + if (nPosition < 1) // XClob is indexed from 1 + throw lang::IllegalArgumentException("nPosition < 1", *this, 0); + --nPosition; // make 0-based + + if (nLength < 0) + throw lang::IllegalArgumentException("nLength < 0", *this, 0); + MutexGuard aGuard(m_aMutex); checkDisposed(Clob_BASE::rBHelper.bDisposed); // TODO do not reset position if it is not necessary m_aBlob->closeInput(); // reset position OUStringBuffer sSegmentBuffer; - sal_Int64 nActPos = 1; - sal_Int32 nActLen = 0; std::vector<char> aSegmentBytes; - // skip irrelevant parts - while( nActPos < nPosition ) + for (;;) { bool bLastRead = m_aBlob->readOneSegment( aSegmentBytes ); - if( bLastRead ) - throw lang::IllegalArgumentException("nPosition out of range", *this, 0); - + // TODO: handle possible case of split UTF-8 character OUString sSegment(aSegmentBytes.data(), aSegmentBytes.size(), RTL_TEXTENCODING_UTF8); - sal_Int32 nStrLen = sSegment.getLength(); - nActPos += nStrLen; - if( nActPos > nPosition ) + + // skip irrelevant parts + if (sSegment.getLength() < nPosition) { - sal_Int32 nCharsToCopy = static_cast<sal_Int32>(nActPos - nPosition); - if( nCharsToCopy > nLength ) - nCharsToCopy = nLength; - // append relevant part of first segment - sSegmentBuffer.append( sSegment.subView(0, nCharsToCopy) ); - nActLen += sSegmentBuffer.getLength(); + if (bLastRead) + throw lang::IllegalArgumentException("nPosition out of range", *this, 0); + nPosition -= sSegment.getLength(); + continue; } - } - // read nLength characters - while( nActLen < nLength ) - { - bool bLastRead = m_aBlob->readOneSegment( aSegmentBytes ); + // Getting here for the first time, nPosition may be > 0, meaning copy start offset. + // This also handles sSegment.getLength() == nPosition case, including nLength == 0. + const sal_Int32 nCharsToCopy = std::min<sal_Int32>(sSegment.getLength() - nPosition, + nLength - sSegmentBuffer.getLength()); + sSegmentBuffer.append(sSegment.subView(nPosition, nCharsToCopy)); + if (sSegmentBuffer.getLength() == nLength) + return sSegmentBuffer.makeStringAndClear(); - OUString sSegment(aSegmentBytes.data(), aSegmentBytes.size(), RTL_TEXTENCODING_UTF8); - sal_Int32 nStrLen = sSegment.getLength(); - if( nActLen + nStrLen > nLength ) - sSegmentBuffer.append(sSegment.subView(0, nLength - nActLen)); - else - sSegmentBuffer.append(sSegment); - nActLen += nStrLen; - - if( bLastRead && nActLen < nLength ) + assert(sSegmentBuffer.getLength() < nLength); + + if (bLastRead) throw lang::IllegalArgumentException("out of range", *this, 0); - } - return sSegmentBuffer.makeStringAndClear(); + nPosition = 0; // No offset after first append + } } uno::Reference< XInputStream > SAL_CALL Clob::getCharacterStream() diff --git a/connectivity/source/drivers/firebird/DatabaseMetaData.cxx b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx index fde8809ec867..eff8097e25bd 100644 --- a/connectivity/source/drivers/firebird/DatabaseMetaData.cxx +++ b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx @@ -1417,7 +1417,7 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTables( uno::Reference< XClob > xClob = xRow->getClob(4); if (xClob.is()) { - aCurrentRow[5] = new ORowSetValueDecorator(xClob->getSubString(0, xClob->length())); + aCurrentRow[5] = new ORowSetValueDecorator(xClob->getSubString(1, xClob->length())); } } diff --git a/connectivity/source/drivers/firebird/ResultSet.cxx b/connectivity/source/drivers/firebird/ResultSet.cxx index 17e87cf8a55d..892e510138a3 100644 --- a/connectivity/source/drivers/firebird/ResultSet.cxx +++ b/connectivity/source/drivers/firebird/ResultSet.cxx @@ -611,7 +611,7 @@ OUString OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT else if(aSqlType == SQL_BLOB && aSqlSubType == static_cast<short>(BlobSubtype::Clob) ) { uno::Reference<XClob> xClob = getClob(nColumnIndex); - return xClob->getSubString( 0, xClob->length() ); + return xClob->getSubString( 1, xClob->length() ); } else { diff --git a/offapi/com/sun/star/sdbc/XClob.idl b/offapi/com/sun/star/sdbc/XClob.idl index bc0d2bc81f0c..045dfc981768 100644 --- a/offapi/com/sun/star/sdbc/XClob.idl +++ b/offapi/com/sun/star/sdbc/XClob.idl @@ -117,7 +117,7 @@ published interface XClob: com::sun::star::uno::XInterface consecutive characters. </p> @param pos - the starting position + the starting position, 1-based @param length the length of the substring @returns |