diff options
Diffstat (limited to 'connectivity/source/drivers/flat/ETable.cxx')
-rw-r--r-- | connectivity/source/drivers/flat/ETable.cxx | 350 |
1 files changed, 213 insertions, 137 deletions
diff --git a/connectivity/source/drivers/flat/ETable.cxx b/connectivity/source/drivers/flat/ETable.cxx index 02cc780a47..14bf8ee5fe 100644 --- a/connectivity/source/drivers/flat/ETable.cxx +++ b/connectivity/source/drivers/flat/ETable.cxx @@ -73,7 +73,7 @@ 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" ); - BOOL bRead = TRUE; + sal_Bool bRead = sal_True; QuotedTokenizedString aHeaderLine; OFlatConnection* pConnection = (OFlatConnection*)m_pConnection; @@ -114,11 +114,11 @@ void OFlatTable::fillColumns(const ::com::sun::star::lang::Locale& _aLocale) m_aScales.clear(); // reserve some space m_aColumns->get().reserve(nFieldCount+1); - m_aTypes.reserve(nFieldCount+1); - m_aPrecisions.reserve(nFieldCount+1); - m_aScales.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()->storesMixedCaseQuotedIdentifiers(); + const sal_Bool bCase = m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers(); CharClass aCharClass(pConnection->getDriver()->getFactory(),_aLocale); // read description const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter(); @@ -126,106 +126,186 @@ void OFlatTable::fillColumns(const ::com::sun::star::lang::Locale& _aLocale) String aColumnName; ::rtl::OUString aTypeName; ::comphelper::UStringMixEqual aCase(bCase); - 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++) + ::std::vector<String> aColumnNames,m_aTypeNames; + m_aTypeNames.resize(nFieldCount); + const sal_Int32 nMaxRowsToScan = pConnection->getMaxRowsToScan(); + sal_Int32 nRowCount = 0; + do { - if ( bHasHeaderLine ) + 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++) { - aHeaderLine.GetTokenSpecial(aColumnName,nStartPosHeaderLine,m_cFieldDelimiter,m_cStringDelimiter); - if ( !aColumnName.Len() ) + if ( nRowCount == 0) { - aColumnName = 'C'; - aColumnName += String::CreateFromInt32(i+1); + 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); } - else + ++nRowCount; + } + while(nRowCount < nMaxRowsToScan && m_pFileStream->ReadByteStringLine(aFirstLine,nEncoding)); + + 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()) { - // no column name so ... - aColumnName = 'C'; - aColumnName += String::CreateFromInt32(i+1); + (aAlias = aColumnNames[i]) += String::CreateFromInt32(++nExprCnt); + aFind = connectivity::find(m_aColumns->get().begin(),m_aColumns->get().end(),aAlias,aCase); } - sal_Int32 eType; - UINT16 nPrecision = 0; - UINT16 nScale = 0; - BOOL bNumeric = FALSE; - ULONG nIndex = 0; + 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; - // first without fielddelimiter - String aField; - aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine,m_cFieldDelimiter,'\0'); - if (aField.Len() == 0 || - (m_cStringDelimiter && m_cStringDelimiter == aField.GetChar(0))) + if ( bNumeric ) { - bNumeric = 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) + // first without fielddelimiter + String aField; + aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine,m_cFieldDelimiter,'\0'); + if (aField.Len() == 0 || + (m_cStringDelimiter && m_cStringDelimiter == aField.GetChar(0))) { - bNumeric = FALSE; + bNumeric = sal_False; + if ( m_cStringDelimiter != '\0' ) + aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); + else + nStartPosFirstLine2 = nStartPosFirstLine; } else { - bNumeric = TRUE; - xub_StrLen nDot = 0; - xub_StrLen nDecimalDelCount = 0; - for (xub_StrLen j = 0; j < aField2.Len(); j++) + String aField2; + if ( m_cStringDelimiter != '\0' ) + aFirstLine.GetTokenSpecial(aField2,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); + else + aField2 = aField; + + if (aField2.Len() == 0) { - const sal_Unicode c = aField2.GetChar(j); - // nur Ziffern und Dezimalpunkt und Tausender-Trennzeichen? - if ( ( !cDecimalDelimiter || c != cDecimalDelimiter ) && - ( !cThousandDelimiter || c != cThousandDelimiter ) && - !aCharClass.isDigit(aField2,j) && - ( j != 0 || (c != '+' && c != '-' ) ) ) - { - bNumeric = FALSE; - break; - } - if (cDecimalDelimiter && c == cDecimalDelimiter) - { - nPrecision = 15; // we have an decimal value - nScale = 2; - ++nDecimalDelCount; - } // if (cDecimalDelimiter && c == cDecimalDelimiter) - if ( c == '.' ) - ++nDot; + bNumeric = sal_False; } - - if (nDecimalDelCount > 1 || nDot > 1 ) // if there is more than one dot it isn't a number - bNumeric = FALSE; - if (bNumeric && cThousandDelimiter) + else { - // Ist der Trenner richtig angegeben? - const String aValue = aField2.GetToken(0,cDecimalDelimiter); - for (sal_Int32 j = aValue.Len() - 4; j >= 0; j -= 4) + 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 = aValue.GetChar(static_cast<sal_uInt16>(j)); - // nur Ziffern und Dezimalpunkt und Tausender-Trennzeichen? - if (c == cThousandDelimiter && j) + const sal_Unicode c = aField2.GetChar(j); + if ( j == nSpaceCount && m_cFieldDelimiter != 32 && c == 32 ) + { + ++nSpaceCount; continue; - else + } + // just digits, decimal- and thousands-delimiter? + if ( ( !cDecimalDelimiter || c != cDecimalDelimiter ) && + ( !cThousandDelimiter || c != cThousandDelimiter ) && + !aCharClass.isDigit(aField2,j) && + ( j != 0 || (c != '+' && c != '-' ) ) ) { - bNumeric = FALSE; + 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; } - } - // jetzt koennte es noch ein Datumsfeld sein - if (!bNumeric) + if (nDecimalDelCount > 1 || nDot > 1 ) // if there is more than one dot it isn't a number + bNumeric = sal_False; + if (bNumeric && cThousandDelimiter) + { + // Is the delimiter correct? + 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)); + // just digits, decimal- and thousands-delimiter? + if (c == cThousandDelimiter && j) + continue; + else + { + bNumeric = sal_False; + break; + } + } + } + + // now also check for a date field + 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 { @@ -243,87 +323,83 @@ void OFlatTable::fillColumns(const ::com::sun::star::lang::Locale& _aLocale) { if (cDecimalDelimiter) { - if(nPrecision) + if(io_nPrecisions) { - eType = DataType::DECIMAL; + io_nType = DataType::DECIMAL; static const ::rtl::OUString s_sDECIMAL(RTL_CONSTASCII_USTRINGPARAM("DECIMAL")); - aTypeName = s_sDECIMAL; + o_sTypeName = s_sDECIMAL; } else { - eType = DataType::DOUBLE; + io_nType = DataType::DOUBLE; static const ::rtl::OUString s_sDOUBLE(RTL_CONSTASCII_USTRINGPARAM("DOUBLE")); - aTypeName = s_sDOUBLE; + o_sTypeName = s_sDOUBLE; } } else - eType = DataType::INTEGER; + { + io_nType = DataType::INTEGER; + io_nPrecisions = 0; + io_nScales = 0; + } nFlags = ColumnSearch::BASIC; } else { - switch (comphelper::getNumberFormatType(m_xNumberFormatter,nIndex)) { case NUMBERFORMAT_DATE: - eType = DataType::DATE; + io_nType = DataType::DATE; { static const ::rtl::OUString s_sDATE(RTL_CONSTASCII_USTRINGPARAM("DATE")); - aTypeName = s_sDATE; + o_sTypeName = s_sDATE; } break; case NUMBERFORMAT_DATETIME: - eType = DataType::TIMESTAMP; + io_nType = DataType::TIMESTAMP; { static const ::rtl::OUString s_sTIMESTAMP(RTL_CONSTASCII_USTRINGPARAM("TIMESTAMP")); - aTypeName = s_sTIMESTAMP; + o_sTypeName = s_sTIMESTAMP; } break; case NUMBERFORMAT_TIME: - eType = DataType::TIME; + io_nType = DataType::TIME; { static const ::rtl::OUString s_sTIME(RTL_CONSTASCII_USTRINGPARAM("TIME")); - aTypeName = s_sTIME; + o_sTypeName = s_sTIME; } break; default: - eType = DataType::VARCHAR; - nPrecision = 0; // nyi: Daten koennen aber laenger sein! - nScale = 0; + io_nType = DataType::VARCHAR; + io_nPrecisions = 0; // nyi: Data can be longer! + io_nScales = 0; { static const ::rtl::OUString s_sVARCHAR(RTL_CONSTASCII_USTRINGPARAM("VARCHAR")); - aTypeName = s_sVARCHAR; + o_sTypeName = s_sVARCHAR; } }; nFlags |= ColumnSearch::CHAR; } - - // check if the columname already exists - String aAlias(aColumnName); - 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()) + } + else + { + String aField; + aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine,m_cFieldDelimiter,'\0'); + if (aField.Len() == 0 || + (m_cStringDelimiter && m_cStringDelimiter == aField.GetChar(0))) { - (aAlias = aColumnName) += String::CreateFromInt32(++nExprCnt); - aFind = connectivity::find(m_aColumns->get().begin(),m_aColumns->get().end(),aAlias,aCase); + 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); } - - sdbcx::OColumn* pColumn = new sdbcx::OColumn(aAlias,aTypeName,::rtl::OUString(),::rtl::OUString(), - ColumnValue::NULLABLE, - nPrecision, - nScale, - eType, - sal_False, - sal_False, - sal_False, - bCase); - Reference< XPropertySet> xCol = pColumn; - m_aColumns->get().push_back(xCol); - m_aTypes.push_back(eType); - m_aPrecisions.push_back(nPrecision); - m_aScales.push_back(nScale); } - m_pFileStream->Seek(m_nStartRowFilePos); } // ------------------------------------------------------------------------- OFlatTable::OFlatTable(sdbcx::OCollection* _pTables,OFlatConnection* _pConnection, @@ -356,11 +432,11 @@ void OFlatTable::construct() 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); + Reference< ::com::sun::star::util::XNumberFormatsSupplier > xSupplier(m_pConnection->getDriver()->getFactory()->createInstanceWithArguments(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.util.NumberFormatsSupplier")),aArg),UNO_QUERY); + m_xNumberFormatter = Reference< ::com::sun::star::util::XNumberFormatter >(m_pConnection->getDriver()->getFactory()->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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; + xProp->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("NullDate"))) >>= m_aNullDate; INetURLObject aURL; aURL.SetURL(getEntry()); @@ -381,7 +457,7 @@ void OFlatTable::construct() sal_Int32 nSize = m_pFileStream->Tell(); m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN); - // Buffersize abhaengig von der Filegroesse + // Buffersize is dependent on the file-size m_pFileStream->SetBufferSize(nSize > 1000000 ? 32768 : nSize > 100000 ? 16384 : nSize > 10000 ? 4096 : 1024); @@ -531,7 +607,7 @@ sal_Bool OFlatTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols,sal *(_rRow->get())[0] = m_nFilePos; if (!bRetrieveData) - return TRUE; + return sal_True; if ( m_bNeedToReadLine ) { sal_Int32 nCurrentPos = 0; @@ -543,7 +619,7 @@ sal_Bool OFlatTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols,sal OFlatConnection* pConnection = (OFlatConnection*)m_pConnection; const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter(); const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter(); - // Felder: + // Fields: xub_StrLen nStartPos = 0; String aStr; OSQLColumns::Vector::const_iterator aIter = _rCols.get().begin(); @@ -558,7 +634,7 @@ sal_Bool OFlatTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols,sal (_rRow->get())[i]->setNull(); else { - // Laengen je nach Datentyp: + // lengths depending on data-type: sal_Int32 nLen, nType = 0; if(bIsTable) @@ -601,7 +677,7 @@ sal_Bool OFlatTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols,sal } break; case DataType::DOUBLE: case DataType::INTEGER: - case DataType::DECIMAL: // #99178# OJ + case DataType::DECIMAL: case DataType::NUMERIC: { @@ -611,11 +687,11 @@ sal_Bool OFlatTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols,sal sal_Unicode* pData = aStrConverted.AllocBuffer(aStr.Len()); const sal_Unicode* pStart = pData; - OSL_ENSURE(cDecimalDelimiter && nType != DataType::INTEGER || - !cDecimalDelimiter && nType == DataType::INTEGER, + OSL_ENSURE((cDecimalDelimiter && nType != DataType::INTEGER) || + (!cDecimalDelimiter && nType == DataType::INTEGER), "FalscherTyp"); - // In Standard-Notation (DezimalPUNKT ohne Tausender-Komma) umwandeln: + // convert to Standard-Notation (DecimalPOINT without thousands-comma): for (xub_StrLen j = 0; j < aStr.Len(); ++j) { const sal_Unicode cChar = aStr.GetChar(j); @@ -623,10 +699,10 @@ sal_Bool OFlatTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols,sal *pData++ = '.'; //aStrConverted.Append( '.' ); else if ( cChar == '.' ) // special case, if decimal seperator isn't '.' we have to put the string after it - continue; // #99189# OJ + continue; else if (cThousandDelimiter && cChar == cThousandDelimiter) { - // weglassen + // leave out } else *pData++ = cChar; @@ -651,7 +727,7 @@ sal_Bool OFlatTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols,sal default: { - // Wert als String in Variable der Row uebernehmen + // Copy Value as String in Row-Variable *(_rRow->get())[i] = ORowSetValue(aStr); } break; @@ -671,7 +747,7 @@ sal_Bool OFlatTable::seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::seekRow" ); OSL_ENSURE(m_pFileStream,"OFlatTable::seekRow: FileStream is NULL!"); // ---------------------------------------------------------- - // Positionierung vorbereiten: + // Prepare positioning: m_nFilePos = nCurPos; switch(eCursorPosition) |