1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <tools/urlobj.hxx>
22 #include <svl/converter.hxx>
23 #include <comphelper/processfactory.hxx>
24 #include <comphelper/string.hxx>
25 #include <comphelper/types.hxx>
26 #include <ucbhelper/content.hxx>
27 #include <svx/txenctab.hxx>
29 #ifndef DISABLE_DBCONNECTIVITY
30 #include <svx/dbcharsethelper.hxx>
33 #include <com/sun/star/sdb/CommandType.hpp>
34 #include <com/sun/star/sdbc/DataType.hpp>
35 #include <com/sun/star/sdbc/XConnection.hpp>
36 #include <com/sun/star/sdbc/XDriver.hpp>
37 #include <com/sun/star/sdbc/XDriverAccess.hpp>
38 #include <com/sun/star/sdbc/DriverManager.hpp>
39 #include <com/sun/star/sdbc/XResultSetUpdate.hpp>
40 #include <com/sun/star/sdbc/XRow.hpp>
41 #include <com/sun/star/sdbc/XRowSet.hpp>
42 #include <com/sun/star/sdbc/XRowUpdate.hpp>
43 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
44 #include <com/sun/star/sdbcx/XAppend.hpp>
45 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
46 #include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
47 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
48 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
49 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
50 #include <com/sun/star/beans/XPropertySet.hpp>
51 #include <com/sun/star/container/XEnumerationAccess.hpp>
52 #include <com/sun/star/lang/XComponent.hpp>
53 #include <com/sun/star/ucb/NameClash.hpp>
54 #include <com/sun/star/ucb/TransferInfo.hpp>
55 #include <com/sun/star/ucb/XCommandInfo.hpp>
57 #include "scerrors.hxx"
60 #include "progress.hxx"
61 #include "formulacell.hxx"
62 #include "editutil.hxx"
63 #include "cellform.hxx"
64 #include "dbdocutl.hxx"
65 #include "dociter.hxx"
66 #include "globstr.hrc"
67 #include "svl/zformat.hxx"
68 #include "svl/intitem.hxx"
69 #include "patattr.hxx"
70 #include "scitems.hxx"
71 #include "docpool.hxx"
72 #include "segmenttree.hxx"
73 #include "docparam.hxx"
74 #include "cellvalue.hxx"
77 #include <boost/unordered_set.hpp>
79 using namespace com::sun::star
;
82 // -----------------------------------------------------------------------
84 #define SC_SERVICE_ROWSET "com.sun.star.sdb.RowSet"
86 //! move to a header file?
87 #define SC_DBPROP_ACTIVECONNECTION "ActiveConnection"
88 #define SC_DBPROP_COMMAND "Command"
89 #define SC_DBPROP_COMMANDTYPE "CommandType"
90 #define SC_DBPROP_PROPCHANGE_NOTIFY "PropertyChangeNotificationEnabled"
92 #define SC_DBPROP_NAME "Name"
93 #define SC_DBPROP_TYPE "Type"
94 #define SC_DBPROP_PRECISION "Precision"
95 #define SC_DBPROP_SCALE "Scale"
97 #define SC_DBPROP_EXTENSION "Extension"
98 #define SC_DBPROP_CHARSET "CharSet"
100 #ifndef DISABLE_DBCONNECTIVITY
104 sal_uLong
lcl_getDBaseConnection(uno::Reference
<sdbc::XDriverManager2
>& _rDrvMgr
, uno::Reference
<sdbc::XConnection
>& _rConnection
, OUString
& _rTabName
, const OUString
& rFullFileName
, rtl_TextEncoding eCharSet
)
107 aURL
.SetSmartProtocol( INET_PROT_FILE
);
108 aURL
.SetSmartURL( rFullFileName
);
109 _rTabName
= aURL
.getBase( INetURLObject::LAST_SEGMENT
, true,
110 INetURLObject::DECODE_UNAMBIGUOUS
);
111 OUString aExtension
= aURL
.getExtension();
112 aURL
.removeSegment();
113 aURL
.removeFinalSlash();
114 OUString aPath
= aURL
.GetMainURL(INetURLObject::NO_DECODE
);
115 uno::Reference
<uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
117 _rDrvMgr
.set( sdbc::DriverManager::create( xContext
) );
121 OUString
aConnUrl("sdbc:dbase:");
124 svxform::ODataAccessCharsetHelper aHelper
;
125 ::std::vector
< rtl_TextEncoding
> aEncodings
;
126 aHelper
.getSupportedTextEncodings( aEncodings
);
127 ::std::vector
< rtl_TextEncoding
>::iterator aIter
= ::std::find(aEncodings
.begin(),aEncodings
.end(),(rtl_TextEncoding
) eCharSet
);
128 if ( aIter
== aEncodings
.end() )
130 OSL_FAIL( "DBaseImport: dbtools::OCharsetMap doesn't know text encoding" );
131 return SCERR_IMPORT_CONNECT
;
132 } // if ( aIter == aMap.end() )
133 OUString aCharSetStr
;
134 if ( RTL_TEXTENCODING_DONTKNOW
!= *aIter
)
135 { // it's not the virtual "system charset"
136 const char* pIanaName
= rtl_getMimeCharsetFromTextEncoding( *aIter
);
137 OSL_ENSURE( pIanaName
, "invalid mime name!" );
139 aCharSetStr
= OUString::createFromAscii( pIanaName
);
142 uno::Sequence
<beans::PropertyValue
> aProps(2);
143 aProps
[0].Name
= SC_DBPROP_EXTENSION
;
144 aProps
[0].Value
<<= OUString( aExtension
);
145 aProps
[1].Name
= SC_DBPROP_CHARSET
;
146 aProps
[1].Value
<<= aCharSetStr
;
148 _rConnection
= _rDrvMgr
->getConnectionWithInfo( aConnUrl
, aProps
);
153 #endif // !DISABLE_DBCONNECTIVITY
155 // -----------------------------------------------------------------------
156 // MoveFile/KillFile/IsDocument: similar to SfxContentHelper
158 bool ScDocShell::MoveFile( const INetURLObject
& rSourceObj
, const INetURLObject
& rDestObj
)
160 bool bMoveData
= true;
161 bool bRet
= true, bKillSource
= false;
162 if ( rSourceObj
.GetProtocol() != rDestObj
.GetProtocol() )
167 OUString aName
= rDestObj
.getName();
168 INetURLObject aDestPathObj
= rDestObj
;
169 aDestPathObj
.removeSegment();
170 aDestPathObj
.setFinalSlash();
174 ::ucbhelper::Content
aDestPath( aDestPathObj
.GetMainURL(INetURLObject::NO_DECODE
),
175 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
>(),
176 comphelper::getProcessComponentContext() );
177 uno::Reference
< ::com::sun::star::ucb::XCommandInfo
> xInfo
= aDestPath
.getCommands();
178 OUString aTransferName
= "transfer";
179 if ( xInfo
->hasCommandByName( aTransferName
) )
181 aDestPath
.executeCommand( aTransferName
, uno::makeAny(
182 ::com::sun::star::ucb::TransferInfo( bMoveData
, rSourceObj
.GetMainURL(INetURLObject::NO_DECODE
), aName
,
183 ::com::sun::star::ucb::NameClash::ERROR
) ) );
187 OSL_FAIL( "transfer command not available" );
190 catch( uno::Exception
& )
192 // ucb may throw different exceptions on failure now
197 KillFile( rSourceObj
);
203 bool ScDocShell::KillFile( const INetURLObject
& rURL
)
208 ::ucbhelper::Content
aCnt( rURL
.GetMainURL(INetURLObject::NO_DECODE
),
209 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
>(),
210 comphelper::getProcessComponentContext() );
211 aCnt
.executeCommand( OUString( "delete" ),
212 comphelper::makeBoolAny( sal_True
) );
214 catch( uno::Exception
& )
216 // ucb may throw different exceptions on failure now
223 bool ScDocShell::IsDocument( const INetURLObject
& rURL
)
228 ::ucbhelper::Content
aCnt( rURL
.GetMainURL(INetURLObject::NO_DECODE
),
229 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
>(),
230 comphelper::getProcessComponentContext() );
231 bRet
= aCnt
.isDocument();
233 catch( uno::Exception
& )
235 // ucb may throw different exceptions on failure now - warning only
236 OSL_FAIL( "Any other exception" );
242 // -----------------------------------------------------------------------
244 #ifndef DISABLE_DBCONNECTIVITY
246 static void lcl_setScalesToColumns(ScDocument
& rDoc
, const vector
<long>& rScales
)
248 SvNumberFormatter
* pFormatter
= rDoc
.GetFormatTable();
252 SCCOL nColCount
= static_cast<SCCOL
>(rScales
.size());
253 for (SCCOL i
= 0; i
< nColCount
; ++i
)
258 sal_uInt32 nOldFormat
;
259 rDoc
.GetNumberFormat(static_cast<SCCOL
>(i
), 0, 0, nOldFormat
);
260 const SvNumberformat
* pOldEntry
= pFormatter
->GetEntry(nOldFormat
);
264 LanguageType eLang
= pOldEntry
->GetLanguage();
265 bool bThousand
, bNegRed
;
266 sal_uInt16 nPrecision
, nLeading
;
267 pOldEntry
->GetFormatSpecialInfo(bThousand
, bNegRed
, nPrecision
, nLeading
);
269 nPrecision
= static_cast<sal_uInt16
>(rScales
[i
]);
270 OUString aNewPicture
= pFormatter
->GenerateFormat(nOldFormat
, eLang
,
271 bThousand
, bNegRed
, nPrecision
, nLeading
);
273 sal_uInt32 nNewFormat
= pFormatter
->GetEntryKey(aNewPicture
, eLang
);
274 if (nNewFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
276 sal_Int32 nErrPos
= 0;
278 bool bOk
= pFormatter
->PutEntry(
279 aNewPicture
, nErrPos
, nNewType
, nNewFormat
, eLang
);
285 ScPatternAttr
aNewAttrs( rDoc
.GetPool() );
286 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
287 rSet
.Put( SfxUInt32Item(ATTR_VALUE_FORMAT
, nNewFormat
) );
288 rDoc
.ApplyPatternAreaTab(static_cast<SCCOL
>(i
), 0, static_cast<SCCOL
>(i
), MAXROW
, 0, aNewAttrs
);
292 #endif // !DISABLE_DBCONNECTIVITY
294 sal_uLong
ScDocShell::DBaseImport( const OUString
& rFullFileName
, rtl_TextEncoding eCharSet
,
295 ScColWidthParam aColWidthParam
[MAXCOLCOUNT
], ScFlatBoolRowSegments
& rRowHeightsRecalc
)
297 #ifdef DISABLE_DBCONNECTIVITY
298 (void) rFullFileName
;
300 (void) aColWidthParam
;
301 (void) rRowHeightsRecalc
;
303 return ERRCODE_IO_GENERAL
;
306 sal_uLong nErr
= eERR_OK
;
310 // Try to get the Text Encoding from the driver
311 if( eCharSet
== RTL_TEXTENCODING_IBM_850
)
312 eCharSet
= RTL_TEXTENCODING_DONTKNOW
;
317 uno::Reference
<sdbc::XDriverManager2
> xDrvMan
;
318 uno::Reference
<sdbc::XConnection
> xConnection
;
319 sal_uLong nRet
= lcl_getDBaseConnection(xDrvMan
,xConnection
,aTabName
,rFullFileName
,eCharSet
);
320 if ( !xConnection
.is() || !xDrvMan
.is() )
322 ::utl::DisposableComponent
aConnectionHelper(xConnection
);
324 ScProgress
aProgress( this, ScGlobal::GetRscString( STR_LOAD_DOC
), 0 );
325 uno::Reference
<lang::XMultiServiceFactory
> xFactory
= comphelper::getProcessServiceFactory();
326 uno::Reference
<sdbc::XRowSet
> xRowSet( xFactory
->createInstance(
327 OUString( SC_SERVICE_ROWSET
) ),
329 ::utl::DisposableComponent
aRowSetHelper(xRowSet
);
330 uno::Reference
<beans::XPropertySet
> xRowProp( xRowSet
, uno::UNO_QUERY
);
331 OSL_ENSURE( xRowProp
.is(), "can't get RowSet" );
332 if (!xRowProp
.is()) return SCERR_IMPORT_CONNECT
;
334 sal_Int32 nType
= sdb::CommandType::TABLE
;
337 aAny
<<= xConnection
;
338 xRowProp
->setPropertyValue( OUString(SC_DBPROP_ACTIVECONNECTION
), aAny
);
341 xRowProp
->setPropertyValue( OUString(SC_DBPROP_COMMANDTYPE
), aAny
);
343 aAny
<<= OUString( aTabName
);
344 xRowProp
->setPropertyValue( OUString(SC_DBPROP_COMMAND
), aAny
);
347 xRowProp
->setPropertyValue( OUString(SC_DBPROP_PROPCHANGE_NOTIFY
), aAny
);
351 uno::Reference
<sdbc::XResultSetMetaData
> xMeta
;
352 uno::Reference
<sdbc::XResultSetMetaDataSupplier
> xMetaSupp( xRowSet
, uno::UNO_QUERY
);
353 if ( xMetaSupp
.is() )
354 xMeta
= xMetaSupp
->getMetaData();
356 nColCount
= xMeta
->getColumnCount(); // this is the number of real columns
358 if ( nColCount
> MAXCOL
+1 )
360 nColCount
= MAXCOL
+1;
361 nErr
= SCWARN_IMPORT_COLUMN_OVERFLOW
; // warning
364 uno::Reference
<sdbc::XRow
> xRow( xRowSet
, uno::UNO_QUERY
);
365 OSL_ENSURE( xRow
.is(), "can't get Row" );
366 if (!xRow
.is()) return SCERR_IMPORT_CONNECT
;
368 // currency flag is not needed for dBase
369 uno::Sequence
<sal_Int32
> aColTypes( nColCount
); // column types
370 sal_Int32
* pTypeArr
= aColTypes
.getArray();
371 for (i
=0; i
<nColCount
; i
++)
372 pTypeArr
[i
] = xMeta
->getColumnType( i
+1 );
375 //! add type descriptions
377 aProgress
.SetState( 0 );
379 vector
<long> aScales(nColCount
, -1);
380 for (i
=0; i
<nColCount
; i
++)
382 OUString aHeader
= xMeta
->getColumnLabel( i
+1 );
384 switch ( pTypeArr
[i
] )
386 case sdbc::DataType::BIT
:
389 case sdbc::DataType::DATE
:
392 case sdbc::DataType::LONGVARCHAR
:
395 case sdbc::DataType::VARCHAR
:
396 aHeader
+= ",C," + OUString::number( xMeta
->getColumnDisplaySize( i
+1 ) );
398 case sdbc::DataType::DECIMAL
:
400 long nPrec
= xMeta
->getPrecision( i
+1 );
401 long nScale
= xMeta
->getScale( i
+1 );
404 SvDbaseConverter::ConvertPrecisionToDbase(
407 OUString::number( nScale
);
413 aDocument
.SetString( static_cast<SCCOL
>(i
), 0, 0, aHeader
);
416 lcl_setScalesToColumns(aDocument
, aScales
);
418 SCROW nRow
= 1; // 0 is column titles
419 sal_Bool bEnd
= false;
420 while ( !bEnd
&& xRowSet
->next() )
422 if ( nRow
<= MAXROW
)
424 bool bSimpleRow
= true;
426 for (i
=0; i
<nColCount
; i
++)
428 ScDatabaseDocUtil::StrData aStrData
;
429 ScDatabaseDocUtil::PutData( &aDocument
, nCol
, nRow
, 0,
430 xRow
, i
+1, pTypeArr
[i
], false,
433 if (aStrData
.mnStrLength
> aColWidthParam
[nCol
].mnMaxTextLen
)
435 aColWidthParam
[nCol
].mnMaxTextLen
= aStrData
.mnStrLength
;
436 aColWidthParam
[nCol
].mnMaxTextRow
= nRow
;
439 if (!aStrData
.mbSimpleText
)
442 aColWidthParam
[nCol
].mbSimpleText
= false;
448 rRowHeightsRecalc
.setTrue(nRow
, nRow
);
451 else // past the end of the spreadsheet
453 bEnd
= sal_True
; // don't continue
454 nErr
= SCWARN_IMPORT_RANGE_OVERFLOW
; // warning message
458 catch ( sdbc::SQLException
& )
460 nErr
= SCERR_IMPORT_CONNECT
;
462 catch ( uno::Exception
& )
464 OSL_FAIL("Unexpected exception in database");
465 nErr
= ERRCODE_IO_GENERAL
;
469 #endif // !DISABLE_DBCONNECTIVITY
472 #ifndef DISABLE_DBCONNECTIVITY
476 inline bool IsAsciiDigit( sal_Unicode c
)
478 return 0x30 <= c
&& c
<= 0x39;
481 inline bool IsAsciiAlpha( sal_Unicode c
)
483 return (0x41 <= c
&& c
<= 0x5a) || (0x61 <= c
&& c
<= 0x7a);
486 void lcl_GetColumnTypes(
487 ScDocShell
& rDocShell
, const ScRange
& rDataRange
, bool bHasFieldNames
,
488 OUString
* pColNames
, sal_Int32
* pColTypes
, sal_Int32
* pColLengths
,
489 sal_Int32
* pColScales
, bool& bHasMemo
, rtl_TextEncoding eCharSet
)
491 // updating of column titles didn't work in 5.2 and isn't always wanted
492 // (saving normally shouldn't modify the document)
493 //! read flag from configuration
494 bool bUpdateTitles
= false;
496 ScDocument
* pDoc
= rDocShell
.GetDocument();
497 SvNumberFormatter
* pNumFmt
= pDoc
->GetFormatTable();
499 SCTAB nTab
= rDataRange
.aStart
.Tab();
500 SCCOL nFirstCol
= rDataRange
.aStart
.Col();
501 SCROW nFirstRow
= rDataRange
.aStart
.Row();
502 SCCOL nLastCol
= rDataRange
.aEnd
.Col();
503 SCROW nLastRow
= rDataRange
.aEnd
.Row();
505 typedef boost::unordered_set
<OUString
, OUStringHash
> StrSetType
;
506 StrSetType aFieldNames
;
509 SCROW nFirstDataRow
= ( bHasFieldNames
? nFirstRow
+ 1 : nFirstRow
);
510 for ( SCCOL nCol
= nFirstCol
; nCol
<= nLastCol
; nCol
++ )
512 bool bTypeDefined
= false;
513 bool bPrecDefined
= false;
514 sal_Int32 nFieldLen
= 0;
515 sal_Int32 nPrecision
= 0;
516 sal_Int32 nDbType
= sdbc::DataType::SQLNULL
;
520 // Feldname[,Type[,Width[,Prec]]]
521 // Typ etc.: L; D; C[,W]; N[,W[,P]]
522 if ( bHasFieldNames
)
524 aString
= pDoc
->GetString(nCol
, nFirstRow
, nTab
);
525 aString
= aString
.toAsciiUpperCase();
526 sal_Int32 nToken
= comphelper::string::getTokenCount(aString
, ',');
529 aFieldName
= aString
.getToken( 0, ',' );
530 aString
= comphelper::string::remove(aString
, ' ');
531 switch ( aString
.getToken( 1, ',' )[0] )
534 nDbType
= sdbc::DataType::BIT
;
536 bTypeDefined
= sal_True
;
537 bPrecDefined
= sal_True
;
540 nDbType
= sdbc::DataType::DATE
;
542 bTypeDefined
= sal_True
;
543 bPrecDefined
= sal_True
;
546 nDbType
= sdbc::DataType::LONGVARCHAR
;
548 bTypeDefined
= sal_True
;
549 bPrecDefined
= sal_True
;
553 nDbType
= sdbc::DataType::VARCHAR
;
554 bTypeDefined
= sal_True
;
555 bPrecDefined
= sal_True
;
558 nDbType
= sdbc::DataType::DECIMAL
;
561 if ( bTypeDefined
&& !nFieldLen
&& nToken
> 2 )
563 nFieldLen
= aString
.getToken( 2, ',' ).toInt32();
564 if ( !bPrecDefined
&& nToken
> 3 )
566 OUString
aTmp( aString
.getToken( 3, ',' ) );
567 if ( CharClass::isAsciiNumeric(aTmp
) )
569 nPrecision
= aTmp
.toInt32();
570 bPrecDefined
= sal_True
;
576 aFieldName
= aString
;
578 // Feldnamen pruefen und ggbf. gueltigen Feldnamen erzeugen.
579 // Erstes Zeichen muss Buchstabe sein,
580 // weitere nur alphanumerisch und Unterstrich erlaubt,
581 // "_DBASELOCK" ist reserviert (obsolet weil erstes Zeichen kein Buchstabe),
582 // keine doppelten Namen.
583 if ( !IsAsciiAlpha( aFieldName
[0] ) )
584 aFieldName
= "N" + aFieldName
;
587 for ( const sal_Unicode
* p
= aFieldName
.getStr(); ( c
= *p
) != 0; p
++ )
589 if ( IsAsciiAlpha( c
) || IsAsciiDigit( c
) || c
== '_' )
590 aTmpStr
+= OUString(c
);
594 aFieldName
= aTmpStr
;
595 if ( aFieldName
.getLength() > 10 )
596 aFieldName
= aFieldName
.copy(0, 10);
598 if (!aFieldNames
.insert(aFieldName
).second
)
599 { // doppelter Feldname, numerisch erweitern
601 OUString
aFixPart( aFieldName
);
605 OUString aVarPart
= OUString::number( nSub
);
606 if ( aFixPart
.getLength() + aVarPart
.getLength() > 10 )
607 aFixPart
= aFixPart
.copy( 0, 10 - aVarPart
.getLength() );
608 aFieldName
= aFixPart
;
609 aFieldName
+= aVarPart
;
610 } while (!aFieldNames
.insert(aFieldName
).second
);
615 aFieldName
= "N" + OUString::number(nCol
+1);
620 ScRefCellValue aCell
;
621 aCell
.assign(*pDoc
, ScAddress(nCol
, nFirstDataRow
, nTab
));
622 if (aCell
.isEmpty() || aCell
.hasString())
623 nDbType
= sdbc::DataType::VARCHAR
;
627 pDoc
->GetNumberFormat( nCol
, nFirstDataRow
, nTab
, nFormat
);
628 switch ( pNumFmt
->GetType( nFormat
) )
630 case NUMBERFORMAT_LOGICAL
:
631 nDbType
= sdbc::DataType::BIT
;
634 case NUMBERFORMAT_DATE
:
635 nDbType
= sdbc::DataType::DATE
;
638 case NUMBERFORMAT_TIME
:
639 case NUMBERFORMAT_DATETIME
:
640 nDbType
= sdbc::DataType::VARCHAR
;
643 nDbType
= sdbc::DataType::DECIMAL
;
647 bool bSdbLenAdjusted
= false;
648 bool bSdbLenBad
= false;
650 if ( nDbType
== sdbc::DataType::VARCHAR
&& !nFieldLen
)
651 { // maximale Feldbreite bestimmen
652 nFieldLen
= pDoc
->GetMaxStringLen( nTab
, nCol
, nFirstDataRow
,
653 nLastRow
, eCharSet
);
654 if ( nFieldLen
== 0 )
657 else if ( nDbType
== sdbc::DataType::DECIMAL
)
658 { // maximale Feldbreite und Nachkommastellen bestimmen
661 nLen
= pDoc
->GetMaxNumberStringLen( nPrec
, nTab
, nCol
,
662 nFirstDataRow
, nLastRow
);
663 // dBaseIII Limit Nachkommastellen: 15
664 if ( nPrecision
> 15 )
668 if ( bPrecDefined
&& nPrecision
!= nPrec
)
669 { // Laenge auf vorgegebene Nachkommastellen anpassen
671 nLen
= sal::static_int_cast
<xub_StrLen
>( nLen
+ ( nPrecision
- nPrec
) );
673 nLen
-= nPrec
+1; // auch den . mit raus
675 if ( nLen
> nFieldLen
&& !bTypeDefined
)
679 if ( nFieldLen
== 0 )
681 else if ( nFieldLen
> 19 )
682 nFieldLen
= 19; // dBaseIII Limit Feldlaenge numerisch: 19
683 if ( nPrecision
&& nFieldLen
< nPrecision
+ 2 )
684 nFieldLen
= nPrecision
+ 2; // 0. muss mit reinpassen
685 // 538 MUST: Sdb internal representation adds 2 to the field length!
686 // To give the user what he wants we must substract it here.
687 //! CAVEAT! There is no way to define a numeric field with a length
688 //! of 1 and no decimals!
689 if ( nFieldLen
== 1 && nPrecision
== 0 )
690 bSdbLenBad
= sal_True
;
691 nFieldLen
= SvDbaseConverter::ConvertPrecisionToOdbc( nFieldLen
, nPrecision
);
692 bSdbLenAdjusted
= sal_True
;
694 if ( nFieldLen
> 254 )
696 if ( nDbType
== sdbc::DataType::VARCHAR
)
697 { // zu lang fuer normales Textfeld => Memofeld
698 nDbType
= sdbc::DataType::LONGVARCHAR
;
703 nFieldLen
= 254; // dumm gelaufen..
706 pColNames
[nField
] = aFieldName
;
707 pColTypes
[nField
] = nDbType
;
708 pColLengths
[nField
] = nFieldLen
;
709 pColScales
[nField
] = nPrecision
;
711 // undo change to field length, reflect reality
712 if ( bSdbLenAdjusted
)
714 nFieldLen
= SvDbaseConverter::ConvertPrecisionToDbase( nFieldLen
, nPrecision
);
715 if ( bSdbLenBad
&& nFieldLen
== 1 )
716 nFieldLen
= 2; // THIS is reality
719 { // Angabe anpassen und ausgeben
720 OUString aOutString
= aFieldName
;
723 case sdbc::DataType::BIT
:
726 case sdbc::DataType::DATE
:
729 case sdbc::DataType::LONGVARCHAR
:
732 case sdbc::DataType::VARCHAR
:
733 aOutString
+= ",C," + OUString::number( nFieldLen
);
735 case sdbc::DataType::DECIMAL
:
736 aOutString
+= ",N," + OUString::number( nFieldLen
) +
737 "," + OUString::number( nPrecision
);
740 if ( !aOutString
.equalsIgnoreAsciiCase( aString
) )
742 pDoc
->SetString( nCol
, nFirstRow
, nTab
, aOutString
);
743 rDocShell
.PostPaint( nCol
, nFirstRow
, nTab
, nCol
, nFirstRow
, nTab
, PAINT_GRID
);
750 inline void lcl_getLongVarCharEditString( OUString
& rString
,
751 const ScRefCellValue
& rCell
, ScFieldEditEngine
& rEditEngine
)
753 if (!rCell
.mpEditText
)
756 rEditEngine
.SetText(*rCell
.mpEditText
);
757 rString
= rEditEngine
.GetText( LINEEND_CRLF
);
760 inline void lcl_getLongVarCharString(
761 OUString
& rString
, ScDocument
& rDoc
, SCCOL nCol
, SCROW nRow
, SCTAB nTab
, SvNumberFormatter
& rNumFmt
)
764 ScAddress
aPos(nCol
, nRow
, nTab
);
765 sal_uInt32 nFormat
= rDoc
.GetNumberFormat(aPos
);
766 rString
= ScCellFormat::GetString(rDoc
, aPos
, nFormat
, &pColor
, rNumFmt
);
771 #endif // !DISABLE_DBCONNECTIVITY
773 sal_uLong
ScDocShell::DBaseExport( const OUString
& rFullFileName
, rtl_TextEncoding eCharSet
, bool& bHasMemo
)
775 #ifdef DISABLE_DBCONNECTIVITY
776 (void) rFullFileName
;
780 return ERRCODE_IO_GENERAL
;
782 // remove the file so the dBase driver doesn't find an invalid file
783 INetURLObject
aDeleteObj( rFullFileName
, INET_PROT_FILE
);
784 KillFile( aDeleteObj
);
786 sal_uLong nErr
= eERR_OK
;
789 SCCOL nFirstCol
, nLastCol
;
790 SCROW nFirstRow
, nLastRow
;
791 SCTAB nTab
= GetSaveTab();
792 aDocument
.GetDataStart( nTab
, nFirstCol
, nFirstRow
);
793 aDocument
.GetCellArea( nTab
, nLastCol
, nLastRow
);
794 if ( nFirstCol
> nLastCol
)
795 nFirstCol
= nLastCol
;
796 if ( nFirstRow
> nLastRow
)
797 nFirstRow
= nLastRow
;
798 ScProgress
aProgress( this, ScGlobal::GetRscString( STR_SAVE_DOC
),
799 nLastRow
- nFirstRow
);
800 SvNumberFormatter
* pNumFmt
= aDocument
.GetFormatTable();
802 sal_Bool bHasFieldNames
= sal_True
;
803 for ( SCCOL nDocCol
= nFirstCol
; nDocCol
<= nLastCol
&& bHasFieldNames
; nDocCol
++ )
804 { // nur Strings in erster Zeile => sind Feldnamen
805 if ( !aDocument
.HasStringData( nDocCol
, nFirstRow
, nTab
) )
806 bHasFieldNames
= false;
809 long nColCount
= nLastCol
- nFirstCol
+ 1;
810 uno::Sequence
<OUString
> aColNames( nColCount
);
811 uno::Sequence
<sal_Int32
> aColTypes( nColCount
);
812 uno::Sequence
<sal_Int32
> aColLengths( nColCount
);
813 uno::Sequence
<sal_Int32
> aColScales( nColCount
);
815 ScRange
aDataRange( nFirstCol
, nFirstRow
, nTab
, nLastCol
, nLastRow
, nTab
);
816 lcl_GetColumnTypes( *this, aDataRange
, bHasFieldNames
,
817 aColNames
.getArray(), aColTypes
.getArray(),
818 aColLengths
.getArray(), aColScales
.getArray(),
819 bHasMemo
, eCharSet
);
820 // also needed for exception catch
822 ScFieldEditEngine
aEditEngine(&aDocument
, aDocument
.GetEditPool());
828 uno::Reference
<sdbc::XDriverManager2
> xDrvMan
;
829 uno::Reference
<sdbc::XConnection
> xConnection
;
830 sal_uLong nRet
= lcl_getDBaseConnection(xDrvMan
,xConnection
,aTabName
,rFullFileName
,eCharSet
);
831 if ( !xConnection
.is() || !xDrvMan
.is() )
833 ::utl::DisposableComponent
aConnectionHelper(xConnection
);
836 uno::Reference
< sdbc::XDriverAccess
> xAccess(xDrvMan
,uno::UNO_QUERY
);
837 uno::Reference
< sdbcx::XDataDefinitionSupplier
> xDDSup( xAccess
->getDriverByURL( xConnection
->getMetaData()->getURL() ), uno::UNO_QUERY
);
839 return SCERR_EXPORT_CONNECT
;
842 uno::Reference
<sdbcx::XTablesSupplier
> xTablesSupp
=xDDSup
->getDataDefinitionByConnection( xConnection
);
843 OSL_ENSURE( xTablesSupp
.is(), "can't get Data Definition" );
844 if (!xTablesSupp
.is()) return SCERR_EXPORT_CONNECT
;
846 uno::Reference
<container::XNameAccess
> xTables
= xTablesSupp
->getTables();
847 OSL_ENSURE( xTables
.is(), "can't get Tables" );
848 if (!xTables
.is()) return SCERR_EXPORT_CONNECT
;
850 uno::Reference
<sdbcx::XDataDescriptorFactory
> xTablesFact( xTables
, uno::UNO_QUERY
);
851 OSL_ENSURE( xTablesFact
.is(), "can't get tables factory" );
852 if (!xTablesFact
.is()) return SCERR_EXPORT_CONNECT
;
854 uno::Reference
<sdbcx::XAppend
> xTablesAppend( xTables
, uno::UNO_QUERY
);
855 OSL_ENSURE( xTablesAppend
.is(), "can't get tables XAppend" );
856 if (!xTablesAppend
.is()) return SCERR_EXPORT_CONNECT
;
858 uno::Reference
<beans::XPropertySet
> xTableDesc
= xTablesFact
->createDataDescriptor();
859 OSL_ENSURE( xTableDesc
.is(), "can't get table descriptor" );
860 if (!xTableDesc
.is()) return SCERR_EXPORT_CONNECT
;
862 aAny
<<= OUString( aTabName
);
863 xTableDesc
->setPropertyValue( OUString(SC_DBPROP_NAME
), aAny
);
867 uno::Reference
<sdbcx::XColumnsSupplier
> xColumnsSupp( xTableDesc
, uno::UNO_QUERY
);
868 OSL_ENSURE( xColumnsSupp
.is(), "can't get columns supplier" );
869 if (!xColumnsSupp
.is()) return SCERR_EXPORT_CONNECT
;
871 uno::Reference
<container::XNameAccess
> xColumns
= xColumnsSupp
->getColumns();
872 OSL_ENSURE( xColumns
.is(), "can't get columns" );
873 if (!xColumns
.is()) return SCERR_EXPORT_CONNECT
;
875 uno::Reference
<sdbcx::XDataDescriptorFactory
> xColumnsFact( xColumns
, uno::UNO_QUERY
);
876 OSL_ENSURE( xColumnsFact
.is(), "can't get columns factory" );
877 if (!xColumnsFact
.is()) return SCERR_EXPORT_CONNECT
;
879 uno::Reference
<sdbcx::XAppend
> xColumnsAppend( xColumns
, uno::UNO_QUERY
);
880 OSL_ENSURE( xColumnsAppend
.is(), "can't get columns XAppend" );
881 if (!xColumnsAppend
.is()) return SCERR_EXPORT_CONNECT
;
883 const OUString
* pColNames
= aColNames
.getConstArray();
884 const sal_Int32
* pColTypes
= aColTypes
.getConstArray();
885 const sal_Int32
* pColLengths
= aColLengths
.getConstArray();
886 const sal_Int32
* pColScales
= aColScales
.getConstArray();
889 for (nCol
=0; nCol
<nColCount
; nCol
++)
891 uno::Reference
<beans::XPropertySet
> xColumnDesc
= xColumnsFact
->createDataDescriptor();
892 OSL_ENSURE( xColumnDesc
.is(), "can't get column descriptor" );
893 if (!xColumnDesc
.is()) return SCERR_EXPORT_CONNECT
;
895 aAny
<<= pColNames
[nCol
];
896 xColumnDesc
->setPropertyValue( OUString(SC_DBPROP_NAME
), aAny
);
898 aAny
<<= pColTypes
[nCol
];
899 xColumnDesc
->setPropertyValue( OUString(SC_DBPROP_TYPE
), aAny
);
901 aAny
<<= pColLengths
[nCol
];
902 xColumnDesc
->setPropertyValue( OUString(SC_DBPROP_PRECISION
), aAny
);
904 aAny
<<= pColScales
[nCol
];
905 xColumnDesc
->setPropertyValue( OUString(SC_DBPROP_SCALE
), aAny
);
907 xColumnsAppend
->appendByDescriptor( xColumnDesc
);
910 xTablesAppend
->appendByDescriptor( xTableDesc
);
912 // get row set for writing
913 uno::Reference
<lang::XMultiServiceFactory
> xFactory
= comphelper::getProcessServiceFactory();
914 uno::Reference
<sdbc::XRowSet
> xRowSet( xFactory
->createInstance(
915 OUString( SC_SERVICE_ROWSET
) ),
917 ::utl::DisposableComponent
aRowSetHelper(xRowSet
);
918 uno::Reference
<beans::XPropertySet
> xRowProp( xRowSet
, uno::UNO_QUERY
);
919 OSL_ENSURE( xRowProp
.is(), "can't get RowSet" );
920 if (!xRowProp
.is()) return SCERR_EXPORT_CONNECT
;
922 aAny
<<= xConnection
;
923 xRowProp
->setPropertyValue( OUString(SC_DBPROP_ACTIVECONNECTION
), aAny
);
925 aAny
<<= (sal_Int32
) sdb::CommandType::TABLE
;
926 xRowProp
->setPropertyValue( OUString(SC_DBPROP_COMMANDTYPE
), aAny
);
928 aAny
<<= OUString( aTabName
);
929 xRowProp
->setPropertyValue( OUString(SC_DBPROP_COMMAND
), aAny
);
935 uno::Reference
<sdbc::XResultSetUpdate
> xResultUpdate( xRowSet
, uno::UNO_QUERY
);
936 OSL_ENSURE( xResultUpdate
.is(), "can't get XResultSetUpdate" );
937 if (!xResultUpdate
.is()) return SCERR_EXPORT_CONNECT
;
939 uno::Reference
<sdbc::XRowUpdate
> xRowUpdate( xRowSet
, uno::UNO_QUERY
);
940 OSL_ENSURE( xRowUpdate
.is(), "can't get XRowUpdate" );
941 if (!xRowUpdate
.is()) return SCERR_EXPORT_CONNECT
;
943 SCROW nFirstDataRow
= ( bHasFieldNames
? nFirstRow
+ 1 : nFirstRow
);
946 for ( nDocRow
= nFirstDataRow
; nDocRow
<= nLastRow
; nDocRow
++ )
948 xResultUpdate
->moveToInsertRow();
950 for (nCol
=0; nCol
<nColCount
; nCol
++)
952 SCCOL nDocCol
= sal::static_int_cast
<SCCOL
>( nFirstCol
+ nCol
);
954 switch (pColTypes
[nCol
])
956 case sdbc::DataType::LONGVARCHAR
:
958 ScRefCellValue aCell
;
959 aCell
.assign(aDocument
, ScAddress(nDocCol
, nDocRow
, nTab
));
960 if (!aCell
.isEmpty())
962 if (aCell
.meType
== CELLTYPE_EDIT
)
963 { // Paragraphs erhalten
964 lcl_getLongVarCharEditString(aString
, aCell
, aEditEngine
);
968 lcl_getLongVarCharString(
969 aString
, aDocument
, nDocCol
, nDocRow
, nTab
, *pNumFmt
);
971 xRowUpdate
->updateString( nCol
+1, aString
);
974 xRowUpdate
->updateNull( nCol
+1 );
978 case sdbc::DataType::VARCHAR
:
979 aString
= aDocument
.GetString(nDocCol
, nDocRow
, nTab
);
980 xRowUpdate
->updateString( nCol
+1, aString
);
981 if ( nErr
== eERR_OK
&& pColLengths
[nCol
] < aString
.getLength() )
982 nErr
= SCWARN_EXPORT_DATALOST
;
985 case sdbc::DataType::DATE
:
987 aDocument
.GetValue( nDocCol
, nDocRow
, nTab
, fVal
);
988 // zwischen 0 Wert und 0 kein Wert unterscheiden
989 sal_Bool bIsNull
= (fVal
== 0.0);
991 bIsNull
= !aDocument
.HasValueData( nDocCol
, nDocRow
, nTab
);
994 xRowUpdate
->updateNull( nCol
+1 );
995 if ( nErr
== eERR_OK
&&
996 aDocument
.HasStringData( nDocCol
, nDocRow
, nTab
) )
997 nErr
= SCWARN_EXPORT_DATALOST
;
1001 Date aDate
= *(pNumFmt
->GetNullDate()); // tools date
1002 aDate
+= (long)fVal
; //! approxfloor?
1003 util::Date
aUnoDate( aDate
.GetDay(), aDate
.GetMonth(), aDate
.GetYear() );
1004 xRowUpdate
->updateDate( nCol
+1, aUnoDate
);
1009 case sdbc::DataType::DECIMAL
:
1010 case sdbc::DataType::BIT
:
1011 aDocument
.GetValue( nDocCol
, nDocRow
, nTab
, fVal
);
1012 if ( fVal
== 0.0 && nErr
== eERR_OK
&&
1013 aDocument
.HasStringData( nDocCol
, nDocRow
, nTab
) )
1014 nErr
= SCWARN_EXPORT_DATALOST
;
1015 if ( pColTypes
[nCol
] == sdbc::DataType::BIT
)
1016 xRowUpdate
->updateBoolean( nCol
+1, ( fVal
!= 0.0 ) );
1018 xRowUpdate
->updateDouble( nCol
+1, fVal
);
1022 OSL_FAIL( "ScDocShell::DBaseExport: unknown FieldType" );
1023 if ( nErr
== eERR_OK
)
1024 nErr
= SCWARN_EXPORT_DATALOST
;
1025 aDocument
.GetValue( nDocCol
, nDocRow
, nTab
, fVal
);
1026 xRowUpdate
->updateDouble( nCol
+1, fVal
);
1030 xResultUpdate
->insertRow();
1032 //! error handling and recovery of old
1033 //! ScDocShell::SbaSdbExport is still missing!
1035 if ( !aProgress
.SetStateOnPercent( nDocRow
- nFirstRow
) )
1037 nErr
= SCERR_EXPORT_DATA
;
1042 comphelper::disposeComponent( xRowSet
);
1043 comphelper::disposeComponent( xConnection
);
1045 catch ( const sdbc::SQLException
& aException
)
1047 sal_Int32 nError
= aException
.ErrorCode
;
1048 #if OSL_DEBUG_LEVEL > 1
1049 fprintf( stderr
, "ScDocShell::DBaseExport: SQLException ErrorCode: %d, SQLState: %s, Message: %s\n",
1050 (int)nError
, OUStringToOString( aException
.SQLState
,
1051 RTL_TEXTENCODING_UTF8
).getStr(), OUStringToOString(
1052 aException
.Message
, RTL_TEXTENCODING_UTF8
).getStr());
1054 if (nError
== 22018 || nError
== 22001)
1056 // SQL error 22018: Character not in target encoding.
1057 // SQL error 22001: String length exceeds field width (after encoding).
1058 bool bEncErr
= (nError
== 22018);
1059 bool bIsOctetTextEncoding
= rtl_isOctetTextEncoding( eCharSet
);
1060 OSL_ENSURE( !bEncErr
|| bIsOctetTextEncoding
, "ScDocShell::DBaseExport: encoding error and not an octect textencoding");
1061 SCCOL nDocCol
= nFirstCol
;
1062 const sal_Int32
* pColTypes
= aColTypes
.getConstArray();
1063 const sal_Int32
* pColLengths
= aColLengths
.getConstArray();
1064 ScHorizontalCellIterator
aIter( &aDocument
, nTab
, nFirstCol
,
1065 nDocRow
, nLastCol
, nDocRow
);
1066 ScRefCellValue
* pCell
= NULL
;
1068 while (bTest
&& ((pCell
= aIter
.GetNext( nDocCol
, nDocRow
)) != NULL
))
1070 SCCOL nCol
= nDocCol
- nFirstCol
;
1071 switch (pColTypes
[nCol
])
1073 case sdbc::DataType::LONGVARCHAR
:
1075 if (pCell
->meType
== CELLTYPE_EDIT
)
1076 lcl_getLongVarCharEditString(aString
, *pCell
, aEditEngine
);
1078 lcl_getLongVarCharString(
1079 aString
, aDocument
, nDocCol
, nDocRow
, nTab
, *pNumFmt
);
1083 case sdbc::DataType::VARCHAR
:
1084 aString
= aDocument
.GetString(nDocCol
, nDocRow
, nTab
);
1087 // NOTE: length of DECIMAL fields doesn't need to be
1088 // checked here, the database driver adjusts the field
1089 // width accordingly.
1097 if (bIsOctetTextEncoding
)
1099 OUString
aOUString( aString
);
1101 if (!aOUString
.convertToString( &aOString
, eCharSet
,
1102 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
1103 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
))
1108 nLen
= aOString
.getLength();
1109 #if OSL_DEBUG_LEVEL > 1
1111 fprintf( stderr
, "ScDocShell::DBaseExport encoding error, string with default replacements: ``%s''\n",
1112 OUStringToOString( aOUString
, eCharSet
).getStr());
1116 nLen
= aString
.getLength() * sizeof(sal_Unicode
);
1118 pColTypes
[nCol
] != sdbc::DataType::LONGVARCHAR
&&
1119 pColLengths
[nCol
] < nLen
)
1122 #if OSL_DEBUG_LEVEL > 1
1123 fprintf( stderr
, "ScDocShell::DBaseExport: field width: %d, encoded length: %d\n",
1124 (int)pColLengths
[nCol
], (int)nLen
);
1131 OUString
sPosition( ScAddress( nDocCol
, nDocRow
, nTab
).GetColRowString());
1132 OUString
sEncoding( SvxTextEncodingTable().GetTextString( eCharSet
));
1133 nErr
= *new TwoStringErrorInfo( (bEncErr
? SCERR_EXPORT_ENCODING
:
1134 SCERR_EXPORT_FIELDWIDTH
), sPosition
, sEncoding
,
1135 ERRCODE_BUTTON_OK
| ERRCODE_MSG_ERROR
);
1137 else if ( !aException
.Message
.isEmpty() )
1138 nErr
= *new StringErrorInfo( (SCERR_EXPORT_SQLEXCEPTION
), aException
.Message
, ERRCODE_BUTTON_OK
| ERRCODE_MSG_ERROR
);
1140 nErr
= SCERR_EXPORT_DATA
;
1142 catch ( uno::Exception
& )
1144 OSL_FAIL("Unexpected exception in database");
1145 nErr
= ERRCODE_IO_GENERAL
;
1149 #endif // !DISABLE_DBCONNECTIVITY
1152 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */