xref: /core/sc/source/ui/docshell/docsh8.cxx (revision 6376fe01859a14a22b2601ff04691ceb894c33d4)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <config_features.h>
21 
22 #include <vcl/errinf.hxx>
23 #include <tools/urlobj.hxx>
24 #include <svl/converter.hxx>
25 #include <svl/numformat.hxx>
26 #include <comphelper/configuration.hxx>
27 #include <comphelper/processfactory.hxx>
28 #include <comphelper/propertysequence.hxx>
29 #include <comphelper/types.hxx>
30 #include <ucbhelper/content.hxx>
31 #include <svx/txenctab.hxx>
32 #include <unotools/sharedunocomponent.hxx>
33 #include <unotools/charclass.hxx>
34 #include <rtl/character.hxx>
35 #include <rtl/tencinfo.h>
36 #include <sal/log.hxx>
37 #include <osl/diagnose.h>
38 #include <comphelper/diagnose_ex.hxx>
39 #include <o3tl/string_view.hxx>
40 
41 #include <com/sun/star/sdb/CommandType.hpp>
42 #include <com/sun/star/sdbc/DataType.hpp>
43 #include <com/sun/star/sdbc/SQLException.hpp>
44 #include <com/sun/star/sdbc/XConnection.hpp>
45 #include <com/sun/star/sdbc/DriverManager.hpp>
46 #include <com/sun/star/sdbc/XResultSetUpdate.hpp>
47 #include <com/sun/star/sdbc/XRow.hpp>
48 #include <com/sun/star/sdbc/XRowSet.hpp>
49 #include <com/sun/star/sdbc/XRowUpdate.hpp>
50 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
51 #include <com/sun/star/sdbcx/XAppend.hpp>
52 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
53 #include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
54 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
55 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
56 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
57 #include <com/sun/star/beans/XPropertySet.hpp>
58 #include <com/sun/star/ucb/NameClash.hpp>
59 #include <com/sun/star/ucb/TransferInfo.hpp>
60 #include <com/sun/star/ucb/XCommandInfo.hpp>
61 
62 #include <scerrors.hxx>
63 #include <docsh.hxx>
64 #include <progress.hxx>
65 #include <editutil.hxx>
66 #include <cellform.hxx>
67 #include <dbdocutl.hxx>
68 #include <dociter.hxx>
69 #include <globstr.hrc>
70 #include <scresid.hxx>
71 #include <svl/zformat.hxx>
72 #include <svl/intitem.hxx>
73 #include <patattr.hxx>
74 #include <scitems.hxx>
75 #include <docpool.hxx>
76 #include <segmenttree.hxx>
77 #include <docparam.hxx>
78 #include <cellvalue.hxx>
79 
80 #include <unordered_set>
81 #include <vector>
82 
83 using namespace com::sun::star;
84 
85 #if HAVE_FEATURE_DBCONNECTIVITY
86 
87 constexpr OUString SC_SERVICE_ROWSET = u"com.sun.star.sdb.RowSet"_ustr;
88 
89 //! move to a header file?
90 constexpr OUString SC_DBPROP_ACTIVECONNECTION = u"ActiveConnection"_ustr;
91 constexpr OUString SC_DBPROP_COMMAND = u"Command"_ustr;
92 constexpr OUString SC_DBPROP_COMMANDTYPE = u"CommandType"_ustr;
93 constexpr OUStringLiteral SC_DBPROP_PROPCHANGE_NOTIFY = u"PropertyChangeNotificationEnabled";
94 
95 constexpr OUString SC_DBPROP_NAME = u"Name"_ustr;
96 constexpr OUStringLiteral SC_DBPROP_TYPE = u"Type";
97 constexpr OUStringLiteral SC_DBPROP_PRECISION = u"Precision";
98 constexpr OUStringLiteral SC_DBPROP_SCALE = u"Scale";
99 
100 constexpr OUString SC_DBPROP_EXTENSION = u"Extension"_ustr;
101 constexpr OUString SC_DBPROP_CHARSET = u"CharSet"_ustr;
102 
103 namespace
104 {
lcl_getDBaseConnection(uno::Reference<sdbc::XDriverManager2> & _rDrvMgr,uno::Reference<sdbc::XConnection> & _rConnection,OUString & _rTabName,std::u16string_view rFullFileName,rtl_TextEncoding eCharSet)105     ErrCode lcl_getDBaseConnection(uno::Reference<sdbc::XDriverManager2>& _rDrvMgr, uno::Reference<sdbc::XConnection>& _rConnection, OUString& _rTabName, std::u16string_view rFullFileName, rtl_TextEncoding eCharSet)
106     {
107         INetURLObject aURL;
108         aURL.SetSmartProtocol( INetProtocol::File );
109         aURL.SetSmartURL( rFullFileName );
110         _rTabName = aURL.getBase( INetURLObject::LAST_SEGMENT, true,
111                 INetURLObject::DecodeMechanism::Unambiguous );
112         OUString aExtension = aURL.getExtension();
113         aURL.removeSegment();
114         aURL.removeFinalSlash();
115         OUString aPath = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
116         const uno::Reference<uno::XComponentContext>& xContext = comphelper::getProcessComponentContext();
117 
118         _rDrvMgr.set( sdbc::DriverManager::create( xContext ) );
119 
120         // get connection
121 
122         const OUString aConnUrl{"sdbc:dbase:" + aPath};
123 
124         // sdbc:dbase is based on the css.sdbc.FILEConnectionProperties UNOIDL service, so we can
125         // transport the raw rtl_TextEncoding value instead of having to translate it into an IANA
126         // character set name string (which might not exist for certain eCharSet values, like
127         // RTL_TEXTENCODING_MS_950):
128         uno::Sequence<beans::PropertyValue> aProps( comphelper::InitPropertySequence({
129                 { SC_DBPROP_EXTENSION, uno::Any(aExtension) },
130                 { SC_DBPROP_CHARSET, uno::Any(eCharSet) }
131             }));
132 
133         _rConnection = _rDrvMgr->getConnectionWithInfo( aConnUrl, aProps );
134         return ERRCODE_NONE;
135     }
136 }
137 
138 #endif // HAVE_FEATURE_DBCONNECTIVITY
139 
140 // MoveFile/KillFile/IsDocument: similar to SfxContentHelper
141 
MoveFile(const INetURLObject & rSourceObj,const INetURLObject & rDestObj)142 bool ScDocShell::MoveFile( const INetURLObject& rSourceObj, const INetURLObject& rDestObj )
143 {
144     bool bMoveData = true;
145     bool bRet = true, bKillSource = false;
146     if ( rSourceObj.GetProtocol() != rDestObj.GetProtocol() )
147     {
148         bMoveData = false;
149         bKillSource = true;
150     }
151     OUString aName = rDestObj.getName();
152     INetURLObject aDestPathObj = rDestObj;
153     aDestPathObj.removeSegment();
154     aDestPathObj.setFinalSlash();
155 
156     try
157     {
158         ::ucbhelper::Content aDestPath( aDestPathObj.GetMainURL(INetURLObject::DecodeMechanism::NONE),
159                             uno::Reference< css::ucb::XCommandEnvironment >(),
160                             comphelper::getProcessComponentContext() );
161         uno::Reference< css::ucb::XCommandInfo > xInfo = aDestPath.getCommands();
162         OUString aTransferName = u"transfer"_ustr;
163         if ( xInfo->hasCommandByName( aTransferName ) )
164         {
165             aDestPath.executeCommand( aTransferName, uno::Any(
166                 css::ucb::TransferInfo( bMoveData, rSourceObj.GetMainURL(INetURLObject::DecodeMechanism::NONE), aName,
167                                                        css::ucb::NameClash::ERROR ) ) );
168         }
169         else
170         {
171             OSL_FAIL( "transfer command not available" );
172         }
173     }
174     catch( uno::Exception& )
175     {
176         // ucb may throw different exceptions on failure now
177         bRet = false;
178     }
179 
180     if ( bKillSource )
181         KillFile( rSourceObj );
182 
183     return bRet;
184 }
185 
KillFile(const INetURLObject & rURL)186 bool ScDocShell::KillFile( const INetURLObject& rURL )
187 {
188     bool bRet = true;
189     try
190     {
191         ::ucbhelper::Content aCnt( rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
192                         uno::Reference< css::ucb::XCommandEnvironment >(),
193                         comphelper::getProcessComponentContext() );
194         aCnt.executeCommand( u"delete"_ustr, css::uno::Any( true ) );
195     }
196     catch( uno::Exception& )
197     {
198         // ucb may throw different exceptions on failure now
199         bRet = false;
200     }
201 
202     return bRet;
203 }
204 
IsDocument(const INetURLObject & rURL)205 bool ScDocShell::IsDocument( const INetURLObject& rURL )
206 {
207     bool bRet = false;
208     try
209     {
210         ::ucbhelper::Content aCnt( rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
211                         uno::Reference< css::ucb::XCommandEnvironment >(),
212                         comphelper::getProcessComponentContext() );
213         bRet = aCnt.isDocument();
214     }
215     catch( uno::Exception& )
216     {
217         // ucb may throw different exceptions on failure now - warning only
218         TOOLS_WARN_EXCEPTION( "sc", "Any other exception" );
219     }
220 
221     return bRet;
222 }
223 
224 #if HAVE_FEATURE_DBCONNECTIVITY
225 
lcl_setScalesToColumns(ScDocument & rDoc,const std::vector<tools::Long> & rScales)226 static void lcl_setScalesToColumns(ScDocument& rDoc, const std::vector<tools::Long>& rScales)
227 {
228     SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
229     if (!pFormatter)
230         return;
231 
232     SCCOL nColCount = static_cast<SCCOL>(rScales.size());
233     for (SCCOL i = 0; i < nColCount; ++i)
234     {
235         if (rScales[i] < 0)
236             continue;
237 
238         sal_uInt32 nOldFormat = rDoc.GetNumberFormat(i, 0, 0);
239         const SvNumberformat* pOldEntry = pFormatter->GetEntry(nOldFormat);
240         if (!pOldEntry)
241             continue;
242 
243         LanguageType eLang = pOldEntry->GetLanguage();
244         bool bThousand, bNegRed;
245         sal_uInt16 nPrecision, nLeading;
246         pOldEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrecision, nLeading);
247 
248         nPrecision = static_cast<sal_uInt16>(rScales[i]);
249         OUString aNewPicture = pFormatter->GenerateFormat(nOldFormat, eLang,
250                                                           bThousand, bNegRed, nPrecision, nLeading);
251 
252         sal_uInt32 nNewFormat = pFormatter->GetEntryKey(aNewPicture, eLang);
253         if (nNewFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
254         {
255             sal_Int32 nErrPos = 0;
256             SvNumFormatType nNewType = SvNumFormatType::ALL;
257             bool bOk = pFormatter->PutEntry(
258                 aNewPicture, nErrPos, nNewType, nNewFormat, eLang);
259 
260             if (!bOk)
261                 continue;
262         }
263 
264         ScPatternAttr aNewAttrs(rDoc.getCellAttributeHelper());
265         aNewAttrs.ItemSetPut(SfxUInt32Item(ATTR_VALUE_FORMAT, nNewFormat));
266         rDoc.ApplyPatternAreaTab(i, 0, i, rDoc.MaxRow(), 0, aNewAttrs);
267     }
268 }
269 
270 #endif // HAVE_FEATURE_DBCONNECTIVITY
271 
DBaseImport(const OUString & rFullFileName,rtl_TextEncoding eCharSet,std::map<SCCOL,ScColWidthParam> & aColWidthParam,ScFlatBoolRowSegments & rRowHeightsRecalc)272 ErrCode ScDocShell::DBaseImport( const OUString& rFullFileName, rtl_TextEncoding eCharSet,
273                                std::map<SCCOL, ScColWidthParam>& aColWidthParam, ScFlatBoolRowSegments& rRowHeightsRecalc )
274 {
275 #if !HAVE_FEATURE_DBCONNECTIVITY
276     (void) rFullFileName;
277     (void) eCharSet;
278     (void) aColWidthParam;
279     (void) rRowHeightsRecalc;
280 
281     return ERRCODE_IO_GENERAL;
282 #else
283 
284     ErrCode nErr = ERRCODE_NONE;
285 
286     try
287     {
288         sal_Int32 nColCount = 0;
289         OUString aTabName;
290         uno::Reference<sdbc::XDriverManager2> xDrvMan;
291         uno::Reference<sdbc::XConnection> xConnection;
292         ErrCode nRet = lcl_getDBaseConnection(xDrvMan,xConnection,aTabName,rFullFileName,eCharSet);
293         if ( !xConnection.is() || !xDrvMan.is() )
294             return nRet;
295         ::utl::DisposableComponent aConnectionHelper(xConnection);
296 
297         ScProgress aProgress( this, ScResId( STR_LOAD_DOC ), 0, true );
298         uno::Reference<lang::XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory();
299         uno::Reference<sdbc::XRowSet> xRowSet( xFactory->createInstance(SC_SERVICE_ROWSET),
300                             uno::UNO_QUERY);
301         ::utl::DisposableComponent aRowSetHelper(xRowSet);
302         uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY );
303         OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
304         if (!xRowProp.is()) return SCERR_IMPORT_CONNECT;
305 
306         xRowProp->setPropertyValue( SC_DBPROP_ACTIVECONNECTION, uno::Any(xConnection) );
307 
308         xRowProp->setPropertyValue( SC_DBPROP_COMMANDTYPE, uno::Any(sdb::CommandType::TABLE) );
309 
310         xRowProp->setPropertyValue( SC_DBPROP_COMMAND, uno::Any(aTabName) );
311 
312         xRowProp->setPropertyValue( SC_DBPROP_PROPCHANGE_NOTIFY, uno::Any(false) );
313 
314         xRowSet->execute();
315 
316         uno::Reference<sdbc::XResultSetMetaData> xMeta;
317         uno::Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp( xRowSet, uno::UNO_QUERY );
318         if ( xMetaSupp.is() )
319             xMeta = xMetaSupp->getMetaData();
320         if ( xMeta.is() )
321             nColCount = xMeta->getColumnCount();    // this is the number of real columns
322 
323         if ( nColCount > m_pDocument->MaxCol()+1 )
324         {
325             nColCount = m_pDocument->MaxCol()+1;
326             nErr = SCWARN_IMPORT_COLUMN_OVERFLOW;    // warning
327         }
328 
329         uno::Reference<sdbc::XRow> xRow( xRowSet, uno::UNO_QUERY );
330         OSL_ENSURE( xRow.is(), "can't get Row" );
331         if (!xRow.is()) return SCERR_IMPORT_CONNECT;
332 
333         // currency flag is not needed for dBase
334         uno::Sequence<sal_Int32> aColTypes( nColCount );    // column types
335         sal_Int32* pTypeArr = aColTypes.getArray();
336         for (sal_Int32 i=0; i<nColCount; i++)
337             pTypeArr[i] = xMeta->getColumnType( i+1 );
338 
339         //  read column names
340         //! add type descriptions
341 
342         aProgress.SetState( 0 );
343 
344         std::vector<tools::Long> aScales(nColCount, -1);
345         for (sal_Int32 i=0; i<nColCount; i++)
346         {
347             OUString aHeader = xMeta->getColumnLabel( i+1 );
348 
349             switch ( pTypeArr[i] )
350             {
351                 case sdbc::DataType::BIT:
352                     aHeader += ",L";
353                     break;
354                 case sdbc::DataType::DATE:
355                     aHeader += ",D";
356                     break;
357                 case sdbc::DataType::LONGVARCHAR:
358                     aHeader += ",M";
359                     break;
360                 case sdbc::DataType::VARCHAR:
361                     aHeader += ",C," + OUString::number( xMeta->getColumnDisplaySize( i+1 ) );
362                     break;
363                 case sdbc::DataType::DECIMAL:
364                     {
365                         tools::Long nPrec = xMeta->getPrecision( i+1 );
366                         tools::Long nScale = xMeta->getScale( i+1 );
367                         aHeader += ",N," +
368                                     OUString::number(
369                                         SvDbaseConverter::ConvertPrecisionToDbase(
370                                             nPrec, nScale ) ) +
371                                     "," +
372                                     OUString::number( nScale );
373                         aScales[i] = nScale;
374                     }
375                     break;
376             }
377 
378             m_pDocument->SetString( static_cast<SCCOL>(i), 0, 0, aHeader );
379         }
380 
381         lcl_setScalesToColumns(*m_pDocument, aScales);
382 
383         SCROW nRow = 1;     // 0 is column titles
384         bool bEnd = false;
385         size_t nErrors(0);
386         while ( !bEnd && xRowSet->next() )
387         {
388             if (nRow <= m_pDocument->MaxRow())
389             {
390                 bool bSimpleRow = true;
391                 SCCOL nCol = 0;
392                 for (sal_Int32 i=0; i<nColCount; i++)
393                 {
394                     ScDatabaseDocUtil::StrData aStrData;
395                     bool bWasError =
396                         ScDatabaseDocUtil::PutData( *m_pDocument, nCol, nRow, 0,
397                                                 xRow, i+1, pTypeArr[i], false,
398                                                 &aStrData );
399 
400                     if (bWasError)
401                         ++nErrors;
402 
403                     if (aStrData.mnStrLength > aColWidthParam[nCol].mnMaxTextLen)
404                     {
405                         aColWidthParam[nCol].mnMaxTextLen = aStrData.mnStrLength;
406                         aColWidthParam[nCol].mnMaxTextRow = nRow;
407                     }
408 
409                     if (!aStrData.mbSimpleText)
410                     {
411                         bSimpleRow = false;
412                         aColWidthParam[nCol].mbSimpleText = false;
413                     }
414 
415                     ++nCol;
416                 }
417                 if (nErrors > 65535 && comphelper::IsFuzzing())
418                 {
419                     bEnd = true;
420                     nErr = ERRCODE_IO_GENERAL;
421                     SAL_WARN("sc", "Too many errors: abandoning.");
422                 }
423                 if (!bSimpleRow)
424                     rRowHeightsRecalc.setTrue(nRow, nRow);
425                 ++nRow;
426             }
427             else        // past the end of the spreadsheet
428             {
429                 bEnd = true;                            // don't continue
430                 nErr = SCWARN_IMPORT_RANGE_OVERFLOW;    // warning message
431             }
432         }
433     }
434     catch ( sdbc::SQLException& )
435     {
436         nErr = SCERR_IMPORT_CONNECT;
437     }
438     catch ( uno::Exception& )
439     {
440         TOOLS_WARN_EXCEPTION( "sc", "Unexpected exception in database");
441         nErr = ERRCODE_IO_GENERAL;
442     }
443 
444     return nErr;
445 #endif // HAVE_FEATURE_DBCONNECTIVITY
446 }
447 
448 #if HAVE_FEATURE_DBCONNECTIVITY
449 
450 namespace {
451 
lcl_GetColumnTypes(ScDocShell & rDocShell,const ScRange & rDataRange,bool bHasFieldNames,OUString * pColNames,sal_Int32 * pColTypes,sal_Int32 * pColLengths,sal_Int32 * pColScales,bool & bHasMemo,rtl_TextEncoding eCharSet)452 void lcl_GetColumnTypes(
453     ScDocShell& rDocShell, const ScRange& rDataRange, bool bHasFieldNames,
454     OUString* pColNames, sal_Int32* pColTypes, sal_Int32* pColLengths,
455     sal_Int32* pColScales, bool& bHasMemo, rtl_TextEncoding eCharSet )
456 {
457     ScDocument& rDoc = rDocShell.GetDocument();
458     ScInterpreterContext& rContext = rDoc.GetNonThreadedContext();
459 
460     SCTAB nTab = rDataRange.aStart.Tab();
461     SCCOL nFirstCol = rDataRange.aStart.Col();
462     SCROW nFirstRow = rDataRange.aStart.Row();
463     SCCOL nLastCol = rDataRange.aEnd.Col();
464     SCROW nLastRow = rDataRange.aEnd.Row();
465 
466     typedef std::unordered_set<OUString> StrSetType;
467     StrSetType aFieldNames;
468 
469     tools::Long nField = 0;
470     SCROW nFirstDataRow = ( bHasFieldNames ? nFirstRow + 1 : nFirstRow );
471     for ( SCCOL nCol = nFirstCol; nCol <= nLastCol; nCol++ )
472     {
473         bool bTypeDefined = false;
474         bool bPrecDefined = false;
475         sal_Int32 nFieldLen = 0;
476         sal_Int32 nPrecision = 0;
477         sal_Int32 nDbType = sdbc::DataType::SQLNULL;
478         OUString aFieldName;
479 
480         // Fieldname[,Type[,Width[,Prec]]]
481         // Type etc.: L; D; C[,W]; N[,W[,P]]
482         if ( bHasFieldNames )
483         {
484             OUString aString {rDoc.GetString(nCol, nFirstRow, nTab).toAsciiUpperCase()};
485             sal_Int32 nIdx {0};
486             aFieldName = aString.getToken( 0, ',', nIdx);
487             if ( nIdx>0 )
488             {
489                 aString = aString.replaceAll(" ", "");
490                 switch ( o3tl::getToken(aString, 0, ',', nIdx )[0] )
491                 {
492                     case 'L' :
493                         nDbType = sdbc::DataType::BIT;
494                         nFieldLen = 1;
495                         bTypeDefined = true;
496                         bPrecDefined = true;
497                         break;
498                     case 'D' :
499                         nDbType = sdbc::DataType::DATE;
500                         nFieldLen = 8;
501                         bTypeDefined = true;
502                         bPrecDefined = true;
503                         break;
504                     case 'M' :
505                         nDbType = sdbc::DataType::LONGVARCHAR;
506                         nFieldLen = 10;
507                         bTypeDefined = true;
508                         bPrecDefined = true;
509                         bHasMemo = true;
510                         break;
511                     case 'C' :
512                         nDbType = sdbc::DataType::VARCHAR;
513                         bTypeDefined = true;
514                         bPrecDefined = true;
515                         break;
516                     case 'N' :
517                         nDbType = sdbc::DataType::DECIMAL;
518                         bTypeDefined = true;
519                         break;
520                 }
521                 if ( bTypeDefined && !nFieldLen && nIdx>0 )
522                 {
523                     nFieldLen = o3tl::toInt32(o3tl::getToken(aString, 0, ',', nIdx ));
524                     if ( !bPrecDefined && nIdx>0 )
525                     {
526                         OUString aTmp( aString.getToken( 0, ',', nIdx ) );
527                         if ( CharClass::isAsciiNumeric(aTmp) )
528                         {
529                             nPrecision = aTmp.toInt32();
530                             if (nPrecision && nFieldLen < nPrecision+1)
531                                 nFieldLen = nPrecision + 1;     // include decimal separator
532                             bPrecDefined = true;
533                         }
534                     }
535                 }
536             }
537 
538             // Check field name and generate valid field name if necessary.
539             // First character has to be alphabetical, subsequent characters
540             // have to be alphanumerical or underscore.
541             // "_DBASELOCK" is reserved (obsolete because first character is
542             // not alphabetical).
543             // No duplicated names.
544             if ( !rtl::isAsciiAlpha(aFieldName[0]) )
545                 aFieldName = "N" + aFieldName;
546             OUStringBuffer aTmpStr;
547             sal_Unicode c;
548             for ( const sal_Unicode* p = aFieldName.getStr(); ( c = *p ) != 0; p++ )
549             {
550                 if ( rtl::isAsciiAlpha(c) || rtl::isAsciiDigit(c) || c == '_' )
551                     aTmpStr.append(c);
552                 else
553                     aTmpStr.append("_");
554             }
555             aFieldName = aTmpStr.makeStringAndClear();
556             if ( aFieldName.getLength() > 10 )
557                 aFieldName = aFieldName.copy(0,  10);
558 
559             if (!aFieldNames.insert(aFieldName).second)
560             {   // Duplicated field name, append numeric suffix.
561                 sal_uInt16 nSub = 1;
562                 OUString aFixPart( aFieldName );
563                 do
564                 {
565                     ++nSub;
566                     OUString aVarPart = OUString::number( nSub );
567                     if ( aFixPart.getLength() + aVarPart.getLength() > 10 )
568                         aFixPart = aFixPart.copy( 0, 10 - aVarPart.getLength() );
569                     aFieldName = aFixPart + aVarPart;
570                 } while (!aFieldNames.insert(aFieldName).second);
571             }
572         }
573         else
574         {
575             aFieldName = "N" + OUString::number(nCol+1);
576         }
577 
578         if ( !bTypeDefined )
579         {   // Field type.
580             ScRefCellValue aCell(rDoc, ScAddress(nCol, nFirstDataRow, nTab));
581             if (aCell.isEmpty() || aCell.hasString())
582                 nDbType = sdbc::DataType::VARCHAR;
583             else
584             {
585                 sal_uInt32 nFormat = rDoc.GetNumberFormat( nCol, nFirstDataRow, nTab );
586                 switch (rContext.NFGetType(nFormat))
587                 {
588                     case SvNumFormatType::LOGICAL :
589                         nDbType = sdbc::DataType::BIT;
590                         nFieldLen = 1;
591                         break;
592                     case SvNumFormatType::DATE :
593                         nDbType = sdbc::DataType::DATE;
594                         nFieldLen = 8;
595                         break;
596                     case SvNumFormatType::TIME :
597                     case SvNumFormatType::DATETIME :
598                         nDbType = sdbc::DataType::VARCHAR;
599                         break;
600                     default:
601                         nDbType = sdbc::DataType::DECIMAL;
602                 }
603             }
604         }
605         // Field length.
606         if ( nDbType == sdbc::DataType::VARCHAR && !nFieldLen )
607         {   // Determine maximum field width.
608             nFieldLen = rDoc.GetMaxStringLen( nTab, nCol, nFirstDataRow,
609                 nLastRow, eCharSet );
610             if ( nFieldLen == 0 )
611                 nFieldLen = 1;
612         }
613         else if ( nDbType == sdbc::DataType::DECIMAL )
614         {   // Determine maximum field width and precision.
615             sal_Int32 nLen;
616             sal_uInt16 nPrec;
617             nLen = rDoc.GetMaxNumberStringLen( nPrec, nTab, nCol,
618                 nFirstDataRow, nLastRow );
619             // dBaseIII precision limit: 15
620             if ( nPrecision > 15 )
621                 nPrecision = 15;
622             if ( nPrec > 15 )
623                 nPrec = 15;
624             if ( bPrecDefined && nPrecision != nPrec )
625             {
626                 if (nPrecision < nPrec)
627                 {
628                     // This is a hairy case. User defined nPrecision but a
629                     // number format has more precision. Modifying a dBase
630                     // field may as well render the resulting file useless for
631                     // an application that relies on its defined structure,
632                     // especially if we are resaving an already existing file.
633                     // So who's right, the user who (or the loaded file that)
634                     // defined the field, or the user who applied the format?
635                     // Commit f59e350d1733125055f1144f8b3b1b0a46f6d1ca gave the
636                     // format a higher priority, which is debatable.
637                     SAL_WARN( "sc", "lcl_GetColumnTypes: conflicting dBase field precision for "
638                             << aFieldName << " (" << nPrecision << "<" << nPrec << ")");
639 
640                     // Adjust length to larger predefined integer part. There
641                     // may be a reason that the field was prepared for larger
642                     // numbers.
643                     if (nFieldLen - nPrecision > nLen - nPrec)
644                         nLen = nFieldLen - (nPrecision ? nPrecision+1 : 0) + 1 + nPrec;
645                     // And override precision.
646                     nPrecision = nPrec;
647                 }
648                 else
649                 {
650 #if 1
651                     // Adjust length to predefined precision.
652                     nLen = nLen + ( nPrecision - nPrec );
653 #else
654     /* If the above override for (nPrecision < nPrec) was not in place then
655      * nPrecision could be 0 and this would be the code path to correctly
656      * calculate nLen. But as is, nPrecision is never 0 here, see CID#982304 */
657 
658                     // Adjust length to predefined precision.
659                     if ( nPrecision )
660                         nLen = nLen + ( nPrecision - nPrec );
661                     else
662                         nLen -= nPrec+1;    // also remove the decimal separator
663 #endif
664                 }
665             }
666             if (nFieldLen < nLen)
667             {
668                 if (!bTypeDefined)
669                     nFieldLen = nLen;
670                 else
671                 {
672                     // Again a hairy case and conflict. Furthermore, the
673                     // larger overall length may be a result of only a higher
674                     // precision obtained from formats.
675                     SAL_WARN( "sc", "lcl_GetColumnTypes: conflicting dBase field length for "
676                             << aFieldName << " (" << nFieldLen << "<" << nLen << ")");
677                     nFieldLen = nLen;
678                 }
679             }
680             if ( !bPrecDefined )
681                 nPrecision = nPrec;
682             if ( nFieldLen == 0 )
683                 nFieldLen = 1;
684             else if ( nFieldLen > 19 )
685                 nFieldLen = 19;     // dBaseIII numeric field length limit: 19
686             if ( nPrecision && nFieldLen < nPrecision + 2 )
687                 nFieldLen = nPrecision + 2;     // 0. must fit into
688             // 538 MUST: Sdb internal representation adds 2 to the field length!
689             // To give the user what he wants we must subtract it here.
690              //! CAVEAT! There is no way to define a numeric field with a length
691              //! of 1 and no decimals!
692             nFieldLen = SvDbaseConverter::ConvertPrecisionToOdbc( nFieldLen, nPrecision );
693         }
694         if ( nFieldLen > 254 )
695         {
696             if ( nDbType == sdbc::DataType::VARCHAR )
697             {   // Too long for a normal text field => memo field.
698                 nDbType = sdbc::DataType::LONGVARCHAR;
699                 nFieldLen = 10;
700                 bHasMemo = true;
701             }
702             else
703                 nFieldLen = 254;                    // bad luck...
704         }
705 
706         pColNames[nField] = aFieldName;
707         pColTypes[nField] = nDbType;
708         pColLengths[nField] = nFieldLen;
709         pColScales[nField] = nPrecision;
710 
711         ++nField;
712     }
713 }
714 
lcl_getLongVarCharEditString(OUString & rString,const ScRefCellValue & rCell,ScFieldEditEngine & rEditEngine)715 void lcl_getLongVarCharEditString( OUString& rString,
716         const ScRefCellValue& rCell, ScFieldEditEngine& rEditEngine )
717 {
718     if (!rCell.getEditText())
719         return;
720 
721     rEditEngine.SetTextCurrentDefaults(*rCell.getEditText());
722     rString = rEditEngine.GetText( LINEEND_CRLF );
723 }
724 
lcl_getLongVarCharString(OUString & rString,ScDocument & rDoc,SCCOL nCol,SCROW nRow,SCTAB nTab,ScInterpreterContext & rContext)725 void lcl_getLongVarCharString(
726     OUString& rString, ScDocument& rDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, ScInterpreterContext& rContext )
727 {
728     const Color* pColor;
729     ScAddress aPos(nCol, nRow, nTab);
730     sal_uInt32 nFormat = rDoc.GetNumberFormat(ScRange(aPos));
731     rString = ScCellFormat::GetString(rDoc, aPos, nFormat, &pColor, &rContext);
732 }
733 
734 }
735 
736 #endif // HAVE_FEATURE_DBCONNECTIVITY
737 
DBaseExport(const OUString & rFullFileName,rtl_TextEncoding eCharSet,bool & bHasMemo)738 ErrCodeMsg ScDocShell::DBaseExport( const OUString& rFullFileName, rtl_TextEncoding eCharSet, bool& bHasMemo )
739 {
740 #if !HAVE_FEATURE_DBCONNECTIVITY
741     (void) rFullFileName;
742     (void) eCharSet;
743     (void) bHasMemo;
744 
745     return ERRCODE_IO_GENERAL;
746 #else
747     // remove the file so the dBase driver doesn't find an invalid file
748     INetURLObject aDeleteObj( rFullFileName, INetProtocol::File );
749     KillFile( aDeleteObj );
750 
751     ErrCodeMsg nErr = ERRCODE_NONE;
752 
753     SCCOL nFirstCol, nLastCol;
754     SCROW  nFirstRow, nLastRow;
755     SCTAB nTab = GetSaveTab();
756     m_pDocument->GetDataStart( nTab, nFirstCol, nFirstRow );
757     m_pDocument->GetCellArea( nTab, nLastCol, nLastRow );
758     if ( nFirstCol > nLastCol )
759         nFirstCol = nLastCol;
760     if ( nFirstRow > nLastRow )
761         nFirstRow = nLastRow;
762     ScProgress aProgress( this, ScResId( STR_SAVE_DOC ),
763                                                     nLastRow - nFirstRow, true );
764     ScInterpreterContext& rContext = m_pDocument->GetNonThreadedContext();
765 
766     bool bHasFieldNames = true;
767     for ( SCCOL nDocCol = nFirstCol; nDocCol <= nLastCol && bHasFieldNames; nDocCol++ )
768     {   // only Strings in first row => are field names
769         if ( !m_pDocument->HasStringData( nDocCol, nFirstRow, nTab ) )
770             bHasFieldNames = false;
771     }
772 
773     sal_Int32 nColCount = nLastCol - nFirstCol + 1;
774     uno::Sequence<OUString> aColNames( nColCount );
775     uno::Sequence<sal_Int32> aColTypes( nColCount );
776     uno::Sequence<sal_Int32> aColLengths( nColCount );
777     uno::Sequence<sal_Int32> aColScales( nColCount );
778 
779     ScRange aDataRange( nFirstCol, nFirstRow, nTab, nLastCol, nLastRow, nTab );
780     lcl_GetColumnTypes( *this, aDataRange, bHasFieldNames,
781                         aColNames.getArray(), aColTypes.getArray(),
782                         aColLengths.getArray(), aColScales.getArray(),
783                         bHasMemo, eCharSet );
784     // also needed for exception catch
785     SCROW nDocRow = 0;
786     ScFieldEditEngine aEditEngine(m_pDocument.get(), m_pDocument->GetEditEnginePool());
787     OUString aString;
788 
789     try
790     {
791         uno::Reference<sdbc::XDriverManager2> xDrvMan;
792         uno::Reference<sdbc::XConnection> xConnection;
793         OUString aTabName;
794         ErrCode nRet = lcl_getDBaseConnection(xDrvMan,xConnection,aTabName,rFullFileName,eCharSet);
795         if ( !xConnection.is() || !xDrvMan.is() )
796             return nRet;
797         ::utl::DisposableComponent aConnectionHelper(xConnection);
798 
799         // get dBase driver
800         uno::Reference< sdbcx::XDataDefinitionSupplier > xDDSup( xDrvMan->getDriverByURL( xConnection->getMetaData()->getURL() ), uno::UNO_QUERY );
801         if ( !xDDSup.is() )
802             return SCERR_EXPORT_CONNECT;
803 
804         // create table
805         uno::Reference<sdbcx::XTablesSupplier> xTablesSupp =xDDSup->getDataDefinitionByConnection( xConnection );
806         OSL_ENSURE( xTablesSupp.is(), "can't get Data Definition" );
807         if (!xTablesSupp.is()) return SCERR_EXPORT_CONNECT;
808 
809         uno::Reference<container::XNameAccess> xTables = xTablesSupp->getTables();
810         OSL_ENSURE( xTables.is(), "can't get Tables" );
811         if (!xTables.is()) return SCERR_EXPORT_CONNECT;
812 
813         uno::Reference<sdbcx::XDataDescriptorFactory> xTablesFact( xTables, uno::UNO_QUERY );
814         OSL_ENSURE( xTablesFact.is(), "can't get tables factory" );
815         if (!xTablesFact.is()) return SCERR_EXPORT_CONNECT;
816 
817         uno::Reference<sdbcx::XAppend> xTablesAppend( xTables, uno::UNO_QUERY );
818         OSL_ENSURE( xTablesAppend.is(), "can't get tables XAppend" );
819         if (!xTablesAppend.is()) return SCERR_EXPORT_CONNECT;
820 
821         uno::Reference<beans::XPropertySet> xTableDesc = xTablesFact->createDataDescriptor();
822         OSL_ENSURE( xTableDesc.is(), "can't get table descriptor" );
823         if (!xTableDesc.is()) return SCERR_EXPORT_CONNECT;
824 
825         xTableDesc->setPropertyValue( SC_DBPROP_NAME, uno::Any(aTabName) );
826 
827         // create columns
828 
829         uno::Reference<sdbcx::XColumnsSupplier> xColumnsSupp( xTableDesc, uno::UNO_QUERY );
830         OSL_ENSURE( xColumnsSupp.is(), "can't get columns supplier" );
831         if (!xColumnsSupp.is()) return SCERR_EXPORT_CONNECT;
832 
833         uno::Reference<container::XNameAccess> xColumns = xColumnsSupp->getColumns();
834         OSL_ENSURE( xColumns.is(), "can't get columns" );
835         if (!xColumns.is()) return SCERR_EXPORT_CONNECT;
836 
837         uno::Reference<sdbcx::XDataDescriptorFactory> xColumnsFact( xColumns, uno::UNO_QUERY );
838         OSL_ENSURE( xColumnsFact.is(), "can't get columns factory" );
839         if (!xColumnsFact.is()) return SCERR_EXPORT_CONNECT;
840 
841         uno::Reference<sdbcx::XAppend> xColumnsAppend( xColumns, uno::UNO_QUERY );
842         OSL_ENSURE( xColumnsAppend.is(), "can't get columns XAppend" );
843         if (!xColumnsAppend.is()) return SCERR_EXPORT_CONNECT;
844 
845         const OUString* pColNames = aColNames.getConstArray();
846         const sal_Int32* pColTypes     = aColTypes.getConstArray();
847         const sal_Int32* pColLengths   = aColLengths.getConstArray();
848         const sal_Int32* pColScales    = aColScales.getConstArray();
849         sal_Int32 nCol;
850 
851         for (nCol=0; nCol<nColCount; nCol++)
852         {
853             uno::Reference<beans::XPropertySet> xColumnDesc = xColumnsFact->createDataDescriptor();
854             OSL_ENSURE( xColumnDesc.is(), "can't get column descriptor" );
855             if (!xColumnDesc.is()) return SCERR_EXPORT_CONNECT;
856 
857             xColumnDesc->setPropertyValue( SC_DBPROP_NAME, uno::Any(pColNames[nCol]) );
858 
859             xColumnDesc->setPropertyValue( SC_DBPROP_TYPE, uno::Any(pColTypes[nCol]) );
860 
861             xColumnDesc->setPropertyValue( SC_DBPROP_PRECISION, uno::Any(pColLengths[nCol]) );
862 
863             xColumnDesc->setPropertyValue( SC_DBPROP_SCALE, uno::Any(pColScales[nCol]) );
864 
865             xColumnsAppend->appendByDescriptor( xColumnDesc );
866         }
867 
868         xTablesAppend->appendByDescriptor( xTableDesc );
869 
870         // get row set for writing
871         uno::Reference<lang::XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory();
872         uno::Reference<sdbc::XRowSet> xRowSet( xFactory->createInstance(SC_SERVICE_ROWSET),
873                             uno::UNO_QUERY);
874         ::utl::DisposableComponent aRowSetHelper(xRowSet);
875         uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY );
876         OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
877         if (!xRowProp.is()) return SCERR_EXPORT_CONNECT;
878 
879         xRowProp->setPropertyValue( SC_DBPROP_ACTIVECONNECTION, uno::Any(xConnection) );
880 
881         xRowProp->setPropertyValue( SC_DBPROP_COMMANDTYPE, uno::Any(sal_Int32(sdb::CommandType::TABLE)) );
882 
883         xRowProp->setPropertyValue( SC_DBPROP_COMMAND, uno::Any(aTabName) );
884 
885         xRowSet->execute();
886 
887         // write data rows
888 
889         uno::Reference<sdbc::XResultSetUpdate> xResultUpdate( xRowSet, uno::UNO_QUERY );
890         OSL_ENSURE( xResultUpdate.is(), "can't get XResultSetUpdate" );
891         if (!xResultUpdate.is()) return SCERR_EXPORT_CONNECT;
892 
893         uno::Reference<sdbc::XRowUpdate> xRowUpdate( xRowSet, uno::UNO_QUERY );
894         OSL_ENSURE( xRowUpdate.is(), "can't get XRowUpdate" );
895         if (!xRowUpdate.is()) return SCERR_EXPORT_CONNECT;
896 
897         SCROW nFirstDataRow = ( bHasFieldNames ? nFirstRow + 1 : nFirstRow );
898         double fVal;
899 
900         for ( nDocRow = nFirstDataRow; nDocRow <= nLastRow; nDocRow++ )
901         {
902             xResultUpdate->moveToInsertRow();
903 
904             for (nCol=0; nCol<nColCount; nCol++)
905             {
906                 SCCOL nDocCol = sal::static_int_cast<SCCOL>( nFirstCol + nCol );
907 
908                 switch (pColTypes[nCol])
909                 {
910                     case sdbc::DataType::LONGVARCHAR:
911                     {
912                         ScRefCellValue aCell(*m_pDocument, ScAddress(nDocCol, nDocRow, nTab));
913                         if (!aCell.isEmpty())
914                         {
915                             if (aCell.getType() == CELLTYPE_EDIT)
916                             {   // preserve paragraphs
917                                 lcl_getLongVarCharEditString(aString, aCell, aEditEngine);
918                             }
919                             else
920                             {
921                                 lcl_getLongVarCharString(
922                                     aString, *m_pDocument, nDocCol, nDocRow, nTab, rContext);
923                             }
924                             xRowUpdate->updateString( nCol+1, aString );
925                         }
926                         else
927                             xRowUpdate->updateNull( nCol+1 );
928                     }
929                     break;
930 
931                     case sdbc::DataType::VARCHAR:
932                         aString = m_pDocument->GetString(nDocCol, nDocRow, nTab);
933                         xRowUpdate->updateString( nCol+1, aString );
934                         if ( nErr == ERRCODE_NONE && pColLengths[nCol] < aString.getLength() )
935                             nErr = SCWARN_EXPORT_DATALOST;
936                         break;
937 
938                     case sdbc::DataType::DATE:
939                         {
940                             fVal = m_pDocument->GetValue( nDocCol, nDocRow, nTab );
941                             // differentiate between 0 with value and 0 no-value
942                             bool bIsNull = (fVal == 0.0);
943                             if ( bIsNull )
944                                 bIsNull = !m_pDocument->HasValueData( nDocCol, nDocRow, nTab );
945                             if ( bIsNull )
946                             {
947                                 xRowUpdate->updateNull( nCol+1 );
948                                 if ( nErr == ERRCODE_NONE &&
949                                         m_pDocument->HasStringData( nDocCol, nDocRow, nTab ) )
950                                     nErr = SCWARN_EXPORT_DATALOST;
951                             }
952                             else
953                             {
954                                 Date aDate = rContext.NFGetNullDate();      // tools date
955                                 aDate.AddDays(fVal);                        //! approxfloor?
956                                 xRowUpdate->updateDate( nCol+1, aDate.GetUNODate() );
957                             }
958                         }
959                         break;
960 
961                     case sdbc::DataType::DECIMAL:
962                     case sdbc::DataType::BIT:
963                         fVal = m_pDocument->GetValue( nDocCol, nDocRow, nTab );
964                         if ( fVal == 0.0 && nErr == ERRCODE_NONE &&
965                                             m_pDocument->HasStringData( nDocCol, nDocRow, nTab ) )
966                             nErr = SCWARN_EXPORT_DATALOST;
967                         if ( pColTypes[nCol] == sdbc::DataType::BIT )
968                             xRowUpdate->updateBoolean( nCol+1, ( fVal != 0.0 ) );
969                         else
970                             xRowUpdate->updateDouble( nCol+1, fVal );
971                         break;
972 
973                     default:
974                         OSL_FAIL( "ScDocShell::DBaseExport: unknown FieldType" );
975                         if ( nErr == ERRCODE_NONE )
976                             nErr = SCWARN_EXPORT_DATALOST;
977                         fVal = m_pDocument->GetValue( nDocCol, nDocRow, nTab );
978                         xRowUpdate->updateDouble( nCol+1, fVal );
979                 }
980             }
981 
982             xResultUpdate->insertRow();
983 
984             //! error handling and recovery of old
985             //! ScDocShell::SbaSdbExport is still missing!
986 
987             aProgress.SetStateOnPercent( nDocRow - nFirstRow );
988         }
989 
990         comphelper::disposeComponent( xRowSet );
991         comphelper::disposeComponent( xConnection );
992     }
993     catch ( const sdbc::SQLException& aException )
994     {
995         sal_Int32 nError = aException.ErrorCode;
996         TOOLS_WARN_EXCEPTION("sc", "ScDocShell::DBaseExport");
997 
998         if (nError == 22018 || nError == 22001)
999         {
1000             // SQL error 22018: Character not in target encoding.
1001             // SQL error 22001: String length exceeds field width (after encoding).
1002             bool bEncErr = (nError == 22018);
1003             bool bIsOctetTextEncoding = rtl_isOctetTextEncoding( eCharSet);
1004             OSL_ENSURE( !bEncErr || bIsOctetTextEncoding, "ScDocShell::DBaseExport: encoding error and not an octet textencoding");
1005             SCCOL nDocCol = nFirstCol;
1006             const sal_Int32* pColTypes = aColTypes.getConstArray();
1007             const sal_Int32* pColLengths = aColLengths.getConstArray();
1008             ScHorizontalCellIterator aIter( *m_pDocument, nTab, nFirstCol,
1009                     nDocRow, nLastCol, nDocRow);
1010             bool bTest = true;
1011             while (bTest)
1012             {
1013                 ScRefCellValue* pCell = aIter.GetNext( nDocCol, nDocRow);
1014                 if (!pCell)
1015                     break;
1016                 SCCOL nCol = nDocCol - nFirstCol;
1017                 switch (pColTypes[nCol])
1018                 {
1019                     case sdbc::DataType::LONGVARCHAR:
1020                         {
1021                             if (pCell->getType() == CELLTYPE_EDIT)
1022                                 lcl_getLongVarCharEditString(aString, *pCell, aEditEngine);
1023                             else
1024                                 lcl_getLongVarCharString(
1025                                     aString, *m_pDocument, nDocCol, nDocRow, nTab, rContext);
1026                         }
1027                         break;
1028 
1029                     case sdbc::DataType::VARCHAR:
1030                         aString = m_pDocument->GetString(nDocCol, nDocRow, nTab);
1031                         break;
1032 
1033                     // NOTE: length of DECIMAL fields doesn't need to be
1034                     // checked here, the database driver adjusts the field
1035                     // width accordingly.
1036 
1037                     default:
1038                         bTest = false;
1039                 }
1040                 if (bTest)
1041                 {
1042                     sal_Int32 nLen;
1043                     if (bIsOctetTextEncoding)
1044                     {
1045                         OString aOString;
1046                         if (!aString.convertToString( &aOString, eCharSet,
1047                                     RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
1048                                     RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
1049                         {
1050                             bTest = false;
1051                             bEncErr = true;
1052                         }
1053                         nLen = aOString.getLength();
1054                         if (!bTest)
1055                             SAL_WARN("sc", "ScDocShell::DBaseExport encoding error, string with default replacements: ``" << aString << "''");
1056                     }
1057                     else
1058                         nLen = aString.getLength() * sizeof(sal_Unicode);
1059                     if (!bEncErr &&
1060                             pColTypes[nCol] != sdbc::DataType::LONGVARCHAR &&
1061                             pColLengths[nCol] < nLen)
1062                     {
1063                         bTest = false;
1064                         SAL_INFO("sc", "ScDocShell::DBaseExport: field width: " << pColLengths[nCol] << ", encoded length: " << nLen);
1065                     }
1066                 }
1067                 else
1068                     bTest = true;
1069             }
1070             OUString sPosition(ScAddress(nDocCol, nDocRow, nTab).GetColRowString());
1071             OUString sEncoding(SvxTextEncodingTable::GetTextString(eCharSet));
1072             nErr = ErrCodeMsg( (bEncErr ? SCERR_EXPORT_ENCODING :
1073                         SCERR_EXPORT_FIELDWIDTH), sPosition, sEncoding,
1074                     DialogMask::ButtonsOk | DialogMask::MessageError);
1075         }
1076         else if ( !aException.Message.isEmpty() )
1077             nErr = ErrCodeMsg( SCERR_EXPORT_SQLEXCEPTION, aException.Message, DialogMask::ButtonsOk | DialogMask::MessageError);
1078         else
1079             nErr = SCERR_EXPORT_DATA;
1080     }
1081     catch ( uno::Exception& )
1082     {
1083         TOOLS_WARN_EXCEPTION( "sc", "Unexpected exception in database");
1084         nErr = ERRCODE_IO_GENERAL;
1085     }
1086 
1087     return nErr;
1088 #endif // HAVE_FEATURE_DBCONNECTIVITY
1089 }
1090 
1091 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1092