| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_connectivity.hxx" |
| |
| #include <ctype.h> |
| #include "flat/ETable.hxx" |
| #include <com/sun/star/sdbc/ColumnValue.hpp> |
| #include <com/sun/star/sdbc/DataType.hpp> |
| #include <com/sun/star/ucb/XContentAccess.hpp> |
| #include <svl/converter.hxx> |
| #include "flat/EConnection.hxx" |
| #include "flat/EColumns.hxx" |
| #include <osl/thread.h> |
| #include <tools/config.hxx> |
| #include <comphelper/sequence.hxx> |
| #include <svl/zforlist.hxx> |
| #include <rtl/math.hxx> |
| #include <stdio.h> //sprintf |
| #include <comphelper/extract.hxx> |
| #include <comphelper/numbers.hxx> |
| #include "flat/EDriver.hxx" |
| #include <com/sun/star/util/NumberFormat.hpp> |
| #include <unotools/configmgr.hxx> |
| #include <i18npool/mslangid.hxx> |
| #include "connectivity/dbconversion.hxx" |
| #include <comphelper/types.hxx> |
| #include "file/quotedstring.hxx" |
| #include <unotools/syslocale.hxx> |
| #include <rtl/logfile.hxx> |
| |
| using namespace ::comphelper; |
| using namespace connectivity; |
| using namespace connectivity::flat; |
| using namespace connectivity::file; |
| using namespace ::cppu; |
| using namespace utl; |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star::ucb; |
| using namespace ::com::sun::star::beans; |
| using namespace ::com::sun::star::sdbcx; |
| using namespace ::com::sun::star::sdbc; |
| using namespace ::com::sun::star::container; |
| using namespace ::com::sun::star::lang; |
| |
| // ------------------------------------------------------------------------- |
| void OFlatTable::fillColumns(const ::com::sun::star::lang::Locale& _aLocale) |
| { |
| RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::fillColumns" ); |
| sal_Bool bRead = sal_True; |
| |
| QuotedTokenizedString aHeaderLine; |
| OFlatConnection* pConnection = (OFlatConnection*)m_pConnection; |
| const rtl_TextEncoding nEncoding = m_pConnection->getTextEncoding(); |
| const sal_Bool bHasHeaderLine = pConnection->isHeaderLine(); |
| if ( bHasHeaderLine ) |
| { |
| while(bRead && !aHeaderLine.Len()) |
| { |
| bRead = m_pFileStream->ReadByteStringLine(aHeaderLine,nEncoding); |
| } |
| m_nStartRowFilePos = m_pFileStream->Tell(); |
| } |
| |
| // read first row |
| QuotedTokenizedString aFirstLine; |
| bRead = m_pFileStream->ReadByteStringLine(aFirstLine,nEncoding); |
| |
| if ( !bHasHeaderLine || !aHeaderLine.Len()) |
| { |
| while(bRead && !aFirstLine.Len()) |
| { |
| bRead = m_pFileStream->ReadByteStringLine(aFirstLine,nEncoding); |
| } |
| // use first row as headerline because we need the number of columns |
| aHeaderLine = aFirstLine; |
| } |
| // column count |
| const xub_StrLen nFieldCount = aHeaderLine.GetTokenCount(m_cFieldDelimiter,m_cStringDelimiter); |
| |
| if(!m_aColumns.isValid()) |
| m_aColumns = new OSQLColumns(); |
| else |
| m_aColumns->get().clear(); |
| |
| m_aTypes.clear(); |
| m_aPrecisions.clear(); |
| m_aScales.clear(); |
| // reserve some space |
| m_aColumns->get().reserve(nFieldCount+1); |
| m_aTypes.assign(nFieldCount+1,DataType::SQLNULL); |
| m_aPrecisions.assign(nFieldCount+1,-1); |
| m_aScales.assign(nFieldCount+1,-1); |
| |
| const sal_Bool bCase = m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers(); |
| CharClass aCharClass(pConnection->getDriver()->getFactory(),_aLocale); |
| // read description |
| const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter(); |
| const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter(); |
| String aColumnName; |
| ::rtl::OUString aTypeName; |
| ::comphelper::UStringMixEqual aCase(bCase); |
| ::std::vector<String> aColumnNames,m_aTypeNames; |
| m_aTypeNames.resize(nFieldCount); |
| const sal_Int32 nMaxRowsToScan = pConnection->getMaxRowsToScan(); |
| sal_Int32 nRowCount = 0; |
| do |
| { |
| xub_StrLen nStartPosHeaderLine = 0; // use for eficient way to get the tokens |
| xub_StrLen nStartPosFirstLine = 0; // use for eficient way to get the tokens |
| xub_StrLen nStartPosFirstLine2 = 0; |
| for (xub_StrLen i = 0; i < nFieldCount; i++) |
| { |
| if ( nRowCount == 0) |
| { |
| if ( bHasHeaderLine ) |
| { |
| aHeaderLine.GetTokenSpecial(aColumnName,nStartPosHeaderLine,m_cFieldDelimiter,m_cStringDelimiter); |
| if ( !aColumnName.Len() ) |
| { |
| aColumnName = 'C'; |
| aColumnName += String::CreateFromInt32(i+1); |
| } |
| } |
| else |
| { |
| // no column name so ... |
| aColumnName = 'C'; |
| aColumnName += String::CreateFromInt32(i+1); |
| } |
| aColumnNames.push_back(aColumnName); |
| } |
| impl_fillColumnInfo_nothrow(aFirstLine,nStartPosFirstLine,nStartPosFirstLine2,m_aTypes[i],m_aPrecisions[i],m_aScales[i],m_aTypeNames[i],cDecimalDelimiter,cThousandDelimiter,aCharClass); |
| } |
| ++nRowCount; |
| } |
| while(nRowCount < nMaxRowsToScan && m_pFileStream->ReadByteStringLine(aFirstLine,nEncoding) && !m_pFileStream->IsEof()); |
| |
| for (xub_StrLen i = 0; i < nFieldCount; i++) |
| { |
| // check if the columname already exists |
| String aAlias(aColumnNames[i]); |
| OSQLColumns::Vector::const_iterator aFind = connectivity::find(m_aColumns->get().begin(),m_aColumns->get().end(),aAlias,aCase); |
| sal_Int32 nExprCnt = 0; |
| while(aFind != m_aColumns->get().end()) |
| { |
| (aAlias = aColumnNames[i]) += String::CreateFromInt32(++nExprCnt); |
| aFind = connectivity::find(m_aColumns->get().begin(),m_aColumns->get().end(),aAlias,aCase); |
| } |
| |
| sdbcx::OColumn* pColumn = new sdbcx::OColumn(aAlias,m_aTypeNames[i],::rtl::OUString(),::rtl::OUString(), |
| ColumnValue::NULLABLE, |
| m_aPrecisions[i], |
| m_aScales[i], |
| m_aTypes[i], |
| sal_False, |
| sal_False, |
| sal_False, |
| bCase); |
| Reference< XPropertySet> xCol = pColumn; |
| m_aColumns->get().push_back(xCol); |
| } |
| m_pFileStream->Seek(m_nStartRowFilePos); |
| } |
| void OFlatTable::impl_fillColumnInfo_nothrow(QuotedTokenizedString& aFirstLine,xub_StrLen& nStartPosFirstLine,xub_StrLen& nStartPosFirstLine2 |
| ,sal_Int32& io_nType,sal_Int32& io_nPrecisions,sal_Int32& io_nScales,String& o_sTypeName |
| ,const sal_Unicode cDecimalDelimiter,const sal_Unicode cThousandDelimiter,const CharClass& aCharClass) |
| { |
| if ( io_nType != DataType::VARCHAR ) |
| { |
| sal_Bool bNumeric = io_nType == DataType::SQLNULL || io_nType == DataType::DOUBLE || io_nType == DataType::DECIMAL || io_nType == DataType::INTEGER; |
| sal_uLong nIndex = 0; |
| |
| if ( bNumeric ) |
| { |
| // first without fielddelimiter |
| String aField; |
| aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine,m_cFieldDelimiter,'\0'); |
| if (aField.Len() == 0 || |
| (m_cStringDelimiter && m_cStringDelimiter == aField.GetChar(0))) |
| { |
| bNumeric = sal_False; |
| if ( m_cStringDelimiter != '\0' ) |
| aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); |
| else |
| nStartPosFirstLine2 = nStartPosFirstLine; |
| } |
| else |
| { |
| String aField2; |
| if ( m_cStringDelimiter != '\0' ) |
| aFirstLine.GetTokenSpecial(aField2,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); |
| else |
| aField2 = aField; |
| |
| if (aField2.Len() == 0) |
| { |
| bNumeric = sal_False; |
| } |
| else |
| { |
| bNumeric = sal_True; |
| xub_StrLen nDot = 0; |
| xub_StrLen nDecimalDelCount = 0; |
| xub_StrLen nSpaceCount = 0; |
| for (xub_StrLen j = 0; j < aField2.Len(); j++) |
| { |
| const sal_Unicode c = aField2.GetChar(j); |
| if ( j == nSpaceCount && m_cFieldDelimiter != 32 && c == 32 ) |
| { |
| ++nSpaceCount; |
| continue; |
| } |
| // nur Ziffern und Dezimalpunkt und Tausender-Trennzeichen? |
| if ( ( !cDecimalDelimiter || c != cDecimalDelimiter ) && |
| ( !cThousandDelimiter || c != cThousandDelimiter ) && |
| !aCharClass.isDigit(aField2,j) && |
| ( j != 0 || (c != '+' && c != '-' ) ) ) |
| { |
| bNumeric = sal_False; |
| break; |
| } |
| if (cDecimalDelimiter && c == cDecimalDelimiter) |
| { |
| io_nPrecisions = 15; // we have an decimal value |
| io_nScales = 2; |
| ++nDecimalDelCount; |
| } // if (cDecimalDelimiter && c == cDecimalDelimiter) |
| if ( c == '.' ) |
| ++nDot; |
| } |
| |
| if (nDecimalDelCount > 1 || nDot > 1 ) // if there is more than one dot it isn't a number |
| bNumeric = sal_False; |
| if (bNumeric && cThousandDelimiter) |
| { |
| // Ist der Trenner richtig angegeben? |
| const String aValue = aField2.GetToken(0,cDecimalDelimiter); |
| for (sal_Int32 j = aValue.Len() - 4; j >= 0; j -= 4) |
| { |
| const sal_Unicode c = aValue.GetChar(static_cast<sal_uInt16>(j)); |
| // nur Ziffern und Dezimalpunkt und Tausender-Trennzeichen? |
| if (c == cThousandDelimiter && j) |
| continue; |
| else |
| { |
| bNumeric = sal_False; |
| break; |
| } |
| } |
| } |
| |
| // jetzt koennte es noch ein Datumsfeld sein |
| if (!bNumeric) |
| { |
| try |
| { |
| nIndex = m_xNumberFormatter->detectNumberFormat(::com::sun::star::util::NumberFormat::ALL,aField2); |
| } |
| catch(Exception&) |
| { |
| } |
| } |
| } |
| } |
| } |
| else if ( io_nType == DataType::DATE || io_nType == DataType::TIMESTAMP || io_nType == DataType::TIME) |
| { |
| String aField; |
| aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine,m_cFieldDelimiter,'\0'); |
| if (aField.Len() == 0 || |
| (m_cStringDelimiter && m_cStringDelimiter == aField.GetChar(0))) |
| { |
| } |
| else |
| { |
| String aField2; |
| if ( m_cStringDelimiter != '\0' ) |
| aFirstLine.GetTokenSpecial(aField2,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); |
| else |
| aField2 = aField; |
| if (aField2.Len() ) |
| { |
| try |
| { |
| nIndex = m_xNumberFormatter->detectNumberFormat(::com::sun::star::util::NumberFormat::ALL,aField2); |
| } |
| catch(Exception&) |
| { |
| } |
| } |
| } |
| } |
| |
| sal_Int32 nFlags = 0; |
| if (bNumeric) |
| { |
| if (cDecimalDelimiter) |
| { |
| if(io_nPrecisions) |
| { |
| io_nType = DataType::DECIMAL; |
| static const ::rtl::OUString s_sDECIMAL(RTL_CONSTASCII_USTRINGPARAM("DECIMAL")); |
| o_sTypeName = s_sDECIMAL; |
| } |
| else |
| { |
| io_nType = DataType::DOUBLE; |
| static const ::rtl::OUString s_sDOUBLE(RTL_CONSTASCII_USTRINGPARAM("DOUBLE")); |
| o_sTypeName = s_sDOUBLE; |
| } |
| } |
| else |
| { |
| io_nType = DataType::INTEGER; |
| io_nPrecisions = 0; |
| io_nScales = 0; |
| } |
| nFlags = ColumnSearch::BASIC; |
| } |
| else |
| { |
| switch (comphelper::getNumberFormatType(m_xNumberFormatter,nIndex)) |
| { |
| case NUMBERFORMAT_DATE: |
| io_nType = DataType::DATE; |
| { |
| static const ::rtl::OUString s_sDATE(RTL_CONSTASCII_USTRINGPARAM("DATE")); |
| o_sTypeName = s_sDATE; |
| } |
| break; |
| case NUMBERFORMAT_DATETIME: |
| io_nType = DataType::TIMESTAMP; |
| { |
| static const ::rtl::OUString s_sTIMESTAMP(RTL_CONSTASCII_USTRINGPARAM("TIMESTAMP")); |
| o_sTypeName = s_sTIMESTAMP; |
| } |
| break; |
| case NUMBERFORMAT_TIME: |
| io_nType = DataType::TIME; |
| { |
| static const ::rtl::OUString s_sTIME(RTL_CONSTASCII_USTRINGPARAM("TIME")); |
| o_sTypeName = s_sTIME; |
| } |
| break; |
| default: |
| io_nType = DataType::VARCHAR; |
| io_nPrecisions = 0; // nyi: Daten koennen aber laenger sein! |
| io_nScales = 0; |
| { |
| static const ::rtl::OUString s_sVARCHAR(RTL_CONSTASCII_USTRINGPARAM("VARCHAR")); |
| o_sTypeName = s_sVARCHAR; |
| } |
| }; |
| nFlags |= ColumnSearch::CHAR; |
| } |
| } |
| else |
| { |
| String aField; |
| aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine,m_cFieldDelimiter,'\0'); |
| if (aField.Len() == 0 || |
| (m_cStringDelimiter && m_cStringDelimiter == aField.GetChar(0))) |
| { |
| if ( m_cStringDelimiter != '\0' ) |
| aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); |
| else |
| nStartPosFirstLine2 = nStartPosFirstLine; |
| } |
| else |
| { |
| String aField2; |
| if ( m_cStringDelimiter != '\0' ) |
| aFirstLine.GetTokenSpecial(aField2,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); |
| } |
| } |
| } |
| // ------------------------------------------------------------------------- |
| OFlatTable::OFlatTable(sdbcx::OCollection* _pTables,OFlatConnection* _pConnection, |
| const ::rtl::OUString& _Name, |
| const ::rtl::OUString& _Type, |
| const ::rtl::OUString& _Description , |
| const ::rtl::OUString& _SchemaName, |
| const ::rtl::OUString& _CatalogName |
| ) : OFlatTable_BASE(_pTables,_pConnection,_Name, |
| _Type, |
| _Description, |
| _SchemaName, |
| _CatalogName) |
| ,m_nStartRowFilePos(0) |
| ,m_nRowPos(0) |
| ,m_nMaxRowCount(0) |
| ,m_cStringDelimiter(_pConnection->getStringDelimiter()) |
| ,m_cFieldDelimiter(_pConnection->getFieldDelimiter()) |
| ,m_bNeedToReadLine(false) |
| { |
| RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::OFlatTable" ); |
| |
| } |
| // ----------------------------------------------------------------------------- |
| void OFlatTable::construct() |
| { |
| RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::construct" ); |
| SvtSysLocale aLocale; |
| ::com::sun::star::lang::Locale aAppLocale(aLocale.GetLocaleDataPtr()->getLocale()); |
| Sequence< ::com::sun::star::uno::Any > aArg(1); |
| aArg[0] <<= aAppLocale; |
| |
| Reference< ::com::sun::star::util::XNumberFormatsSupplier > xSupplier(m_pConnection->getDriver()->getFactory()->createInstanceWithArguments(::rtl::OUString::createFromAscii("com.sun.star.util.NumberFormatsSupplier"),aArg),UNO_QUERY); |
| m_xNumberFormatter = Reference< ::com::sun::star::util::XNumberFormatter >(m_pConnection->getDriver()->getFactory()->createInstance(::rtl::OUString::createFromAscii("com.sun.star.util.NumberFormatter")),UNO_QUERY); |
| m_xNumberFormatter->attachNumberFormatsSupplier(xSupplier); |
| Reference<XPropertySet> xProp(xSupplier->getNumberFormatSettings(),UNO_QUERY); |
| xProp->getPropertyValue(::rtl::OUString::createFromAscii("NullDate")) >>= m_aNullDate; |
| |
| INetURLObject aURL; |
| aURL.SetURL(getEntry()); |
| |
| if(aURL.getExtension() != rtl::OUString(m_pConnection->getExtension())) |
| aURL.setExtension(m_pConnection->getExtension()); |
| |
| String aFileName = aURL.GetMainURL(INetURLObject::NO_DECODE); |
| |
| m_pFileStream = createStream_simpleError( aFileName,STREAM_READWRITE | STREAM_NOCREATE | STREAM_SHARE_DENYWRITE); |
| |
| if(!m_pFileStream) |
| m_pFileStream = createStream_simpleError( aFileName,STREAM_READ | STREAM_NOCREATE | STREAM_SHARE_DENYNONE); |
| |
| if(m_pFileStream) |
| { |
| m_pFileStream->Seek(STREAM_SEEK_TO_END); |
| sal_Int32 nSize = m_pFileStream->Tell(); |
| m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN); |
| |
| // Buffersize abhaengig von der Filegroesse |
| m_pFileStream->SetBufferSize(nSize > 1000000 ? 32768 : |
| nSize > 100000 ? 16384 : |
| nSize > 10000 ? 4096 : 1024); |
| |
| fillColumns(aAppLocale); |
| |
| refreshColumns(); |
| } |
| } |
| // ------------------------------------------------------------------------- |
| String OFlatTable::getEntry() |
| { |
| RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::getEntry" ); |
| ::rtl::OUString sURL; |
| try |
| { |
| Reference< XResultSet > xDir = m_pConnection->getDir()->getStaticResultSet(); |
| Reference< XRow> xRow(xDir,UNO_QUERY); |
| ::rtl::OUString sName; |
| ::rtl::OUString sExt; |
| |
| INetURLObject aURL; |
| xDir->beforeFirst(); |
| static const ::rtl::OUString s_sSeparator(RTL_CONSTASCII_USTRINGPARAM("/")); |
| while(xDir->next()) |
| { |
| sName = xRow->getString(1); |
| aURL.SetSmartProtocol(INET_PROT_FILE); |
| String sUrl = m_pConnection->getURL() + s_sSeparator + sName; |
| aURL.SetSmartURL( sUrl ); |
| |
| // cut the extension |
| sExt = aURL.getExtension(); |
| |
| // name and extension have to coincide |
| if ( m_pConnection->matchesExtension( sExt ) ) |
| { |
| if ( sExt.getLength() ) |
| sName = sName.replaceAt(sName.getLength()-(sExt.getLength()+1),sExt.getLength()+1,::rtl::OUString()); |
| if ( sName == m_Name ) |
| { |
| Reference< XContentAccess > xContentAccess( xDir, UNO_QUERY ); |
| sURL = xContentAccess->queryContentIdentifierString(); |
| break; |
| } |
| } |
| } |
| xDir->beforeFirst(); // move back to before first record |
| } |
| catch(Exception&) |
| { |
| OSL_ASSERT(0); |
| } |
| return sURL.getStr(); |
| } |
| // ------------------------------------------------------------------------- |
| void OFlatTable::refreshColumns() |
| { |
| RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::refreshColumns" ); |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| |
| TStringVector aVector; |
| aVector.reserve(m_aColumns->get().size()); |
| |
| for(OSQLColumns::Vector::const_iterator aIter = m_aColumns->get().begin();aIter != m_aColumns->get().end();++aIter) |
| aVector.push_back(Reference< XNamed>(*aIter,UNO_QUERY)->getName()); |
| |
| if(m_pColumns) |
| m_pColumns->reFill(aVector); |
| else |
| m_pColumns = new OFlatColumns(this,m_aMutex,aVector); |
| } |
| |
| // ------------------------------------------------------------------------- |
| void SAL_CALL OFlatTable::disposing(void) |
| { |
| RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::disposing" ); |
| OFileTable::disposing(); |
| ::osl::MutexGuard aGuard(m_aMutex); |
| m_aColumns = NULL; |
| } |
| // ------------------------------------------------------------------------- |
| Sequence< Type > SAL_CALL OFlatTable::getTypes( ) throw(RuntimeException) |
| { |
| Sequence< Type > aTypes = OTable_TYPEDEF::getTypes(); |
| ::std::vector<Type> aOwnTypes; |
| aOwnTypes.reserve(aTypes.getLength()); |
| const Type* pBegin = aTypes.getConstArray(); |
| const Type* pEnd = pBegin + aTypes.getLength(); |
| for(;pBegin != pEnd;++pBegin) |
| { |
| if(!(*pBegin == ::getCppuType((const Reference<XKeysSupplier>*)0) || |
| *pBegin == ::getCppuType((const Reference<XRename>*)0) || |
| *pBegin == ::getCppuType((const Reference<XIndexesSupplier>*)0) || |
| *pBegin == ::getCppuType((const Reference<XAlterTable>*)0) || |
| *pBegin == ::getCppuType((const Reference<XDataDescriptorFactory>*)0))) |
| { |
| aOwnTypes.push_back(*pBegin); |
| } |
| } |
| Type *pTypes = aOwnTypes.empty() ? 0 : &aOwnTypes[0]; |
| return Sequence< Type >(pTypes, aOwnTypes.size()); |
| } |
| |
| // ------------------------------------------------------------------------- |
| Any SAL_CALL OFlatTable::queryInterface( const Type & rType ) throw(RuntimeException) |
| { |
| if( rType == ::getCppuType((const Reference<XKeysSupplier>*)0) || |
| rType == ::getCppuType((const Reference<XIndexesSupplier>*)0) || |
| rType == ::getCppuType((const Reference<XRename>*)0) || |
| rType == ::getCppuType((const Reference<XAlterTable>*)0) || |
| rType == ::getCppuType((const Reference<XDataDescriptorFactory>*)0)) |
| return Any(); |
| |
| Any aRet = OTable_TYPEDEF::queryInterface(rType); |
| return aRet.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< ::com::sun::star::lang::XUnoTunnel*> (this)); |
| } |
| |
| //-------------------------------------------------------------------------- |
| Sequence< sal_Int8 > OFlatTable::getUnoTunnelImplementationId() |
| { |
| static ::cppu::OImplementationId * pId = 0; |
| if (! pId) |
| { |
| ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); |
| if (! pId) |
| { |
| static ::cppu::OImplementationId aId; |
| pId = &aId; |
| } |
| } |
| return pId->getImplementationId(); |
| } |
| |
| // com::sun::star::lang::XUnoTunnel |
| //------------------------------------------------------------------ |
| sal_Int64 OFlatTable::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException) |
| { |
| RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::getSomething" ); |
| return (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(), rId.getConstArray(), 16 ) ) |
| ? reinterpret_cast< sal_Int64 >( this ) |
| : OFlatTable_BASE::getSomething(rId); |
| } |
| //------------------------------------------------------------------ |
| sal_Bool OFlatTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols,sal_Bool bIsTable,sal_Bool bRetrieveData) |
| { |
| RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::fetchRow" ); |
| *(_rRow->get())[0] = m_nFilePos; |
| |
| if (!bRetrieveData) |
| return sal_True; |
| if ( m_bNeedToReadLine ) |
| { |
| sal_Int32 nCurrentPos = 0; |
| m_pFileStream->Seek(m_nFilePos); |
| readLine(nCurrentPos); |
| m_bNeedToReadLine = false; |
| } |
| |
| OFlatConnection* pConnection = (OFlatConnection*)m_pConnection; |
| const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter(); |
| const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter(); |
| // Felder: |
| xub_StrLen nStartPos = 0; |
| String aStr; |
| OSQLColumns::Vector::const_iterator aIter = _rCols.get().begin(); |
| OSQLColumns::Vector::const_iterator aEnd = _rCols.get().end(); |
| const OValueRefVector::Vector::size_type nCount = _rRow->get().size(); |
| for (OValueRefVector::Vector::size_type i = 1; aIter != aEnd && i < nCount; |
| ++aIter, i++) |
| { |
| m_aCurrentLine.GetTokenSpecial(aStr,nStartPos,m_cFieldDelimiter,m_cStringDelimiter); |
| |
| if (aStr.Len() == 0) |
| (_rRow->get())[i]->setNull(); |
| else |
| { |
| // Laengen je nach Datentyp: |
| sal_Int32 nLen, |
| nType = 0; |
| if(bIsTable) |
| { |
| nLen = m_aPrecisions[i-1]; |
| nType = m_aTypes[i-1]; |
| } |
| else |
| { |
| Reference< XPropertySet> xColumn = *aIter; |
| xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)) >>= nLen; |
| xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType; |
| } |
| switch(nType) |
| { |
| case DataType::TIMESTAMP: |
| case DataType::DATE: |
| case DataType::TIME: |
| { |
| try |
| { |
| double nRes = m_xNumberFormatter->convertStringToNumber(::com::sun::star::util::NumberFormat::ALL,aStr); |
| |
| switch(nType) |
| { |
| case DataType::DATE: |
| *(_rRow->get())[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(nRes,m_aNullDate)); |
| break; |
| case DataType::TIMESTAMP: |
| *(_rRow->get())[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDateTime(nRes,m_aNullDate)); |
| break; |
| default: |
| *(_rRow->get())[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(nRes)); |
| } |
| } |
| catch(Exception&) |
| { |
| (_rRow->get())[i]->setNull(); |
| } |
| } break; |
| case DataType::DOUBLE: |
| case DataType::INTEGER: |
| case DataType::DECIMAL: // #99178# OJ |
| case DataType::NUMERIC: |
| { |
| |
| String aStrConverted; |
| if ( DataType::INTEGER != nType ) |
| { |
| sal_Unicode* pData = aStrConverted.AllocBuffer(aStr.Len()); |
| const sal_Unicode* pStart = pData; |
| |
| OSL_ENSURE(cDecimalDelimiter && nType != DataType::INTEGER || |
| !cDecimalDelimiter && nType == DataType::INTEGER, |
| "FalscherTyp"); |
| |
| // In Standard-Notation (DezimalPUNKT ohne Tausender-Komma) umwandeln: |
| for (xub_StrLen j = 0; j < aStr.Len(); ++j) |
| { |
| const sal_Unicode cChar = aStr.GetChar(j); |
| if (cDecimalDelimiter && cChar == cDecimalDelimiter) |
| *pData++ = '.'; |
| //aStrConverted.Append( '.' ); |
| else if ( cChar == '.' ) // special case, if decimal seperator isn't '.' we have to put the string after it |
| continue; // #99189# OJ |
| else if (cThousandDelimiter && cChar == cThousandDelimiter) |
| { |
| // weglassen |
| } |
| else |
| *pData++ = cChar; |
| //aStrConverted.Append(cChar); |
| } // for (xub_StrLen j = 0; j < aStr.Len(); ++j) |
| aStrConverted.ReleaseBufferAccess(xub_StrLen(pData - pStart)); |
| } // if ( DataType::INTEGER != nType ) |
| else |
| { |
| aStrConverted = aStr; |
| if ( cThousandDelimiter ) |
| aStrConverted.EraseAllChars(cThousandDelimiter); |
| } |
| const double nVal = ::rtl::math::stringToDouble(aStrConverted,'.',',',NULL,NULL); |
| |
| // #99178# OJ |
| if ( DataType::DECIMAL == nType || DataType::NUMERIC == nType ) |
| *(_rRow->get())[i] = ::rtl::OUString::valueOf(nVal); |
| else |
| *(_rRow->get())[i] = nVal; |
| } break; |
| |
| default: |
| { |
| // Wert als String in Variable der Row uebernehmen |
| *(_rRow->get())[i] = ORowSetValue(aStr); |
| } |
| break; |
| } // switch(nType) |
| (_rRow->get())[i]->setTypeKind(nType); |
| } |
| } |
| return sal_True; |
| } |
| void OFlatTable::refreshHeader() |
| { |
| m_nRowPos = 0; |
| } |
| // ----------------------------------------------------------------------------- |
| sal_Bool OFlatTable::seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) |
| { |
| RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::seekRow" ); |
| OSL_ENSURE(m_pFileStream,"OFlatTable::seekRow: FileStream is NULL!"); |
| // ---------------------------------------------------------- |
| // Positionierung vorbereiten: |
| m_nFilePos = nCurPos; |
| |
| switch(eCursorPosition) |
| { |
| case IResultSetHelper::FIRST: |
| m_nRowPos = 0; |
| // run through |
| case IResultSetHelper::NEXT: |
| { |
| ++m_nRowPos; |
| ::std::map<sal_Int32,TRowPositionsInFile::iterator>::const_iterator aFind = m_aRowPosToFilePos.find(m_nRowPos); |
| m_bNeedToReadLine = aFind != m_aRowPosToFilePos.end(); |
| if ( m_bNeedToReadLine ) |
| { |
| m_nFilePos = aFind->second->first; |
| nCurPos = aFind->second->second; |
| } // if ( m_bNeedToReadLine ) |
| else |
| { |
| if ( m_nRowPos == 1 ) |
| m_nFilePos = m_nStartRowFilePos; |
| m_pFileStream->Seek(m_nFilePos); |
| if ( m_pFileStream->IsEof() || !readLine(nCurPos) /*|| !checkHeaderLine()*/) |
| { |
| m_nMaxRowCount = m_nRowPos -1; |
| return sal_False; |
| } // if ( m_pFileStream->IsEof() || !readLine(nCurPos) /*|| !checkHeaderLine()*/) |
| |
| TRowPositionsInFile::iterator aPos = m_aFilePosToEndLinePos.insert(TRowPositionsInFile::value_type(m_nFilePos,nCurPos)).first; |
| m_aRowPosToFilePos.insert(::std::map<sal_Int32,TRowPositionsInFile::iterator>::value_type(m_nRowPos,aPos)); |
| } |
| } |
| |
| break; |
| case IResultSetHelper::PRIOR: |
| --m_nRowPos; |
| if(m_nRowPos > 0) |
| { |
| TRowPositionsInFile::iterator aPositions = m_aRowPosToFilePos[m_nRowPos]; |
| m_nFilePos = aPositions->first; |
| nCurPos = aPositions->second; |
| m_bNeedToReadLine = true; |
| } |
| else |
| m_nRowPos = 0; |
| |
| break; |
| case IResultSetHelper::LAST: |
| if ( m_nMaxRowCount ) |
| { |
| ::std::map<sal_Int32,TRowPositionsInFile::iterator>::reverse_iterator aLastPos = m_aRowPosToFilePos.rbegin(); |
| m_nRowPos = aLastPos->first; |
| m_nFilePos = aLastPos->second->first; |
| nCurPos = aLastPos->second->second; |
| |
| //m_pFileStream->Seek(m_nFilePos); |
| m_bNeedToReadLine = true; |
| //if ( m_pFileStream->IsEof() /*|| !checkHeaderLine()*/ || !readLine(nCurPos) ) |
| // return sal_False; |
| } |
| else |
| { |
| while(seekRow(IResultSetHelper::NEXT,1,nCurPos)) ; // run through after last row |
| // now I know all |
| seekRow(IResultSetHelper::PRIOR,1,nCurPos); |
| } |
| break; |
| case IResultSetHelper::RELATIVE: |
| if(nOffset > 0) |
| { |
| for(sal_Int32 i = 0;i<nOffset;++i) |
| seekRow(IResultSetHelper::NEXT,1,nCurPos); |
| } |
| else if(nOffset < 0) |
| { |
| for(sal_Int32 i = nOffset;i;++i) |
| seekRow(IResultSetHelper::PRIOR,1,nCurPos); |
| } |
| break; |
| case IResultSetHelper::ABSOLUTE: |
| { |
| if(nOffset < 0) |
| nOffset = m_nRowPos + nOffset; |
| ::std::map<sal_Int32,TRowPositionsInFile::iterator>::const_iterator aIter = m_aRowPosToFilePos.find(nOffset); |
| if(aIter != m_aRowPosToFilePos.end()) |
| { |
| m_nFilePos = aIter->second->first; |
| nCurPos = aIter->second->second; |
| //m_pFileStream->Seek(m_nFilePos); |
| m_bNeedToReadLine = true; |
| //if ( m_pFileStream->IsEof() /*|| !checkHeaderLine()*/ || !readLine(nCurPos) ) |
| // return sal_False; |
| } |
| else if(m_nMaxRowCount && nOffset > m_nMaxRowCount) // offset is outside the table |
| { |
| m_nRowPos = m_nMaxRowCount; |
| return sal_False; |
| } |
| else |
| { |
| aIter = m_aRowPosToFilePos.upper_bound(nOffset); |
| if(aIter == m_aRowPosToFilePos.end()) |
| { |
| ::std::map<sal_Int32,TRowPositionsInFile::iterator>::reverse_iterator aLastPos = m_aRowPosToFilePos.rbegin(); |
| m_nRowPos = aLastPos->first; |
| nCurPos = m_nFilePos = aLastPos->second->first; |
| while(m_nRowPos != nOffset) |
| seekRow(IResultSetHelper::NEXT,1,nCurPos); |
| } |
| else |
| { |
| --aIter; |
| m_nRowPos = aIter->first; |
| m_nFilePos = aIter->second->first; |
| nCurPos = aIter->second->second; |
| //m_pFileStream->Seek(m_nFilePos); |
| m_bNeedToReadLine = true; |
| //if ( m_pFileStream->IsEof() /*|| !checkHeaderLine()*/ || !readLine(nCurPos) ) |
| // return sal_False; |
| } |
| } |
| } |
| |
| break; |
| case IResultSetHelper::BOOKMARK: |
| { |
| TRowPositionsInFile::const_iterator aFind = m_aFilePosToEndLinePos.find(nOffset); |
| m_bNeedToReadLine = aFind != m_aFilePosToEndLinePos.end(); |
| if ( m_bNeedToReadLine ) |
| { |
| m_nFilePos = aFind->first; |
| nCurPos = aFind->second; |
| } |
| else |
| { |
| m_nFilePos = nOffset; |
| m_pFileStream->Seek(nOffset); |
| if (m_pFileStream->IsEof() || !readLine(nCurPos) ) |
| return sal_False; |
| } |
| break; |
| } |
| } |
| |
| //nCurPos = m_nFilePos; |
| |
| return sal_True; |
| } |
| // ----------------------------------------------------------------------------- |
| sal_Bool OFlatTable::readLine(sal_Int32& _rnCurrentPos) |
| { |
| RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::readLine" ); |
| const rtl_TextEncoding nEncoding = m_pConnection->getTextEncoding(); |
| m_pFileStream->ReadByteStringLine(m_aCurrentLine,nEncoding); |
| if (m_pFileStream->IsEof()) |
| return sal_False; |
| |
| QuotedTokenizedString sLine = m_aCurrentLine; // check if the string continues on next line |
| while( (sLine.GetString().GetTokenCount(m_cStringDelimiter) % 2) != 1 ) |
| { |
| m_pFileStream->ReadByteStringLine(sLine,nEncoding); |
| if ( !m_pFileStream->IsEof() ) |
| { |
| m_aCurrentLine.GetString().Append('\n'); |
| m_aCurrentLine.GetString() += sLine.GetString(); |
| sLine = m_aCurrentLine; |
| } |
| else |
| break; |
| } |
| _rnCurrentPos = m_pFileStream->Tell(); |
| return sal_True; |
| } |
| |