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 .
20 #include "calc/CTable.hxx"
21 #include <com/sun/star/sdbc/ColumnValue.hpp>
22 #include <com/sun/star/sdbc/DataType.hpp>
23 #include <com/sun/star/sdbc/XRow.hpp>
24 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
25 #include <com/sun/star/sheet/XSpreadsheet.hpp>
26 #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
27 #include <com/sun/star/sheet/XCellRangesQuery.hpp>
28 #include <com/sun/star/sheet/XDatabaseRanges.hpp>
29 #include <com/sun/star/sheet/XDatabaseRange.hpp>
30 #include <com/sun/star/sheet/XCellRangeReferrer.hpp>
31 #include <com/sun/star/sheet/XUsedAreaCursor.hpp>
32 #include <com/sun/star/sheet/CellFlags.hpp>
33 #include <com/sun/star/sheet/FormulaResult.hpp>
34 #include <com/sun/star/util/NumberFormat.hpp>
35 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
36 #include <com/sun/star/text/XText.hpp>
37 #include <svl/converter.hxx>
38 #include "calc/CConnection.hxx"
39 #include "component/CColumns.hxx"
40 #include <connectivity/sdbcx/VColumn.hxx>
41 #include <rtl/ustrbuf.hxx>
42 #include <osl/thread.h>
43 #include <cppuhelper/queryinterface.hxx>
44 #include <comphelper/sequence.hxx>
45 #include <svl/zforlist.hxx>
46 #include <rtl/math.hxx>
47 #include <comphelper/extract.hxx>
48 #include <connectivity/dbexception.hxx>
49 #include <connectivity/dbconversion.hxx>
50 #include <comphelper/types.hxx>
52 using namespace connectivity
;
53 using namespace connectivity::calc
;
54 using namespace connectivity::file
;
55 using namespace ::cppu
;
56 using namespace ::dbtools
;
57 using namespace ::com::sun::star::uno
;
58 using namespace ::com::sun::star::beans
;
59 using namespace ::com::sun::star::sdbcx
;
60 using namespace ::com::sun::star::sdbc
;
61 using namespace ::com::sun::star::container
;
62 using namespace ::com::sun::star::lang
;
63 using namespace ::com::sun::star::sheet
;
64 using namespace ::com::sun::star::table
;
65 using namespace ::com::sun::star::text
;
66 using namespace ::com::sun::star::util
;
69 static void lcl_UpdateArea( const Reference
<XCellRange
>& xUsedRange
, sal_Int32
& rEndCol
, sal_Int32
& rEndRow
)
71 // update rEndCol, rEndRow if any non-empty cell in xUsedRange is right/below
73 const Reference
<XCellRangesQuery
> xUsedQuery( xUsedRange
, UNO_QUERY
);
74 if ( xUsedQuery
.is() )
76 const sal_Int16 nContentFlags
=
77 CellFlags::STRING
| CellFlags::VALUE
| CellFlags::DATETIME
| CellFlags::FORMULA
| CellFlags::ANNOTATION
;
79 const Reference
<XSheetCellRanges
> xUsedRanges
= xUsedQuery
->queryContentCells( nContentFlags
);
80 const Sequence
<CellRangeAddress
> aAddresses
= xUsedRanges
->getRangeAddresses();
82 const sal_Int32 nCount
= aAddresses
.getLength();
83 const CellRangeAddress
* pData
= aAddresses
.getConstArray();
84 for ( sal_Int32 i
=0; i
<nCount
; i
++ )
86 rEndCol
= pData
[i
].EndColumn
> rEndCol
? pData
[i
].EndColumn
: rEndCol
;
87 rEndRow
= pData
[i
].EndRow
> rEndRow
? pData
[i
].EndRow
: rEndRow
;
92 static void lcl_GetDataArea( const Reference
<XSpreadsheet
>& xSheet
, sal_Int32
& rColumnCount
, sal_Int32
& rRowCount
)
94 Reference
<XSheetCellCursor
> xCursor
= xSheet
->createCursor();
95 Reference
<XCellRangeAddressable
> xRange( xCursor
, UNO_QUERY
);
98 rColumnCount
= rRowCount
= 0;
102 // first find the contiguous cell area starting at A1
104 xCursor
->collapseToSize( 1, 1 ); // single (first) cell
105 xCursor
->collapseToCurrentRegion(); // contiguous data area
107 CellRangeAddress aRegionAddr
= xRange
->getRangeAddress();
108 sal_Int32 nEndCol
= aRegionAddr
.EndColumn
;
109 sal_Int32 nEndRow
= aRegionAddr
.EndRow
;
111 Reference
<XUsedAreaCursor
> xUsed( xCursor
, UNO_QUERY
);
114 // The used area from XUsedAreaCursor includes visible attributes.
115 // If the used area is larger than the contiguous cell area, find non-empty
116 // cells in that area.
118 xUsed
->gotoEndOfUsedArea( false );
119 CellRangeAddress aUsedAddr
= xRange
->getRangeAddress();
121 if ( aUsedAddr
.EndColumn
> aRegionAddr
.EndColumn
)
123 Reference
<XCellRange
> xUsedRange
= xSheet
->getCellRangeByPosition(
124 aRegionAddr
.EndColumn
+ 1, 0, aUsedAddr
.EndColumn
, aUsedAddr
.EndRow
);
125 lcl_UpdateArea( xUsedRange
, nEndCol
, nEndRow
);
128 if ( aUsedAddr
.EndRow
> aRegionAddr
.EndRow
)
130 // only up to the last column of aRegionAddr, the other columns are handled above
131 Reference
<XCellRange
> xUsedRange
= xSheet
->getCellRangeByPosition(
132 0, aRegionAddr
.EndRow
+ 1, aRegionAddr
.EndColumn
, aUsedAddr
.EndRow
);
133 lcl_UpdateArea( xUsedRange
, nEndCol
, nEndRow
);
137 rColumnCount
= nEndCol
+ 1; // number of columns
138 rRowCount
= nEndRow
; // first row (headers) is not counted
141 static CellContentType
lcl_GetContentOrResultType( const Reference
<XCell
>& xCell
)
143 CellContentType eCellType
= xCell
->getType();
144 if ( eCellType
== CellContentType_FORMULA
)
146 Reference
<XPropertySet
> xProp( xCell
, UNO_QUERY
);
149 xProp
->getPropertyValue( "FormulaResultType" ) >>= eCellType
; // type of formula result
151 catch (UnknownPropertyException
&)
153 eCellType
= CellContentType_VALUE
; // if FormulaResultType property not available
159 static Reference
<XCell
> lcl_GetUsedCell( const Reference
<XSpreadsheet
>& xSheet
, sal_Int32 nDocColumn
, sal_Int32 nDocRow
)
161 Reference
<XCell
> xCell
= xSheet
->getCellByPosition( nDocColumn
, nDocRow
);
162 if ( xCell
.is() && xCell
->getType() == CellContentType_EMPTY
)
164 // get first non-empty cell
166 Reference
<XCellRangeAddressable
> xAddr( xSheet
, UNO_QUERY
);
169 CellRangeAddress aTotalRange
= xAddr
->getRangeAddress();
170 sal_Int32 nLastRow
= aTotalRange
.EndRow
;
171 Reference
<XCellRangesQuery
> xQuery( xSheet
->getCellRangeByPosition( nDocColumn
, nDocRow
, nDocColumn
, nLastRow
), UNO_QUERY
);
174 // queryIntersection to get a ranges object
175 Reference
<XSheetCellRanges
> xRanges
= xQuery
->queryIntersection( aTotalRange
);
178 Reference
<XEnumerationAccess
> xCells
= xRanges
->getCells();
181 Reference
<XEnumeration
> xEnum
= xCells
->createEnumeration();
182 if ( xEnum
.is() && xEnum
->hasMoreElements() )
184 // get first non-empty cell from enumeration
185 xCell
.set(xEnum
->nextElement(),UNO_QUERY
);
187 // otherwise, keep empty cell
196 static bool lcl_HasTextInColumn( const Reference
<XSpreadsheet
>& xSheet
, sal_Int32 nDocColumn
, sal_Int32 nDocRow
)
198 // look for any text cell or text result in the column
200 Reference
<XCellRangeAddressable
> xAddr( xSheet
, UNO_QUERY
);
203 CellRangeAddress aTotalRange
= xAddr
->getRangeAddress();
204 sal_Int32 nLastRow
= aTotalRange
.EndRow
;
205 Reference
<XCellRangesQuery
> xQuery( xSheet
->getCellRangeByPosition( nDocColumn
, nDocRow
, nDocColumn
, nLastRow
), UNO_QUERY
);
208 // are there text cells in the column?
209 Reference
<XSheetCellRanges
> xTextContent
= xQuery
->queryContentCells( CellFlags::STRING
);
210 if ( xTextContent
.is() && xTextContent
->hasElements() )
213 // are there formulas with text results in the column?
214 Reference
<XSheetCellRanges
> xTextFormula
= xQuery
->queryFormulaCells( FormulaResult::STRING
);
215 if ( xTextFormula
.is() && xTextFormula
->hasElements() )
223 static void lcl_GetColumnInfo( const Reference
<XSpreadsheet
>& xSheet
, const Reference
<XNumberFormats
>& xFormats
,
224 sal_Int32 nDocColumn
, sal_Int32 nStartRow
, bool bHasHeaders
,
225 OUString
& rName
, sal_Int32
& rDataType
, bool& rCurrency
)
227 //! avoid duplicate field names
229 // get column name from first row, if range contains headers
233 Reference
<XText
> xHeaderText( xSheet
->getCellByPosition( nDocColumn
, nStartRow
), UNO_QUERY
);
234 if ( xHeaderText
.is() )
235 rName
= xHeaderText
->getString();
238 // get column type from first data row
240 sal_Int32 nDataRow
= nStartRow
;
243 Reference
<XCell
> xDataCell
= lcl_GetUsedCell( xSheet
, nDocColumn
, nDataRow
);
245 Reference
<XPropertySet
> xProp( xDataCell
, UNO_QUERY
);
248 rCurrency
= false; // set to true for currency below
250 const CellContentType eCellType
= lcl_GetContentOrResultType( xDataCell
);
251 // #i35178# use "text" type if there is any text cell in the column
252 if ( eCellType
== CellContentType_TEXT
|| lcl_HasTextInColumn( xSheet
, nDocColumn
, nDataRow
) )
253 rDataType
= DataType::VARCHAR
;
254 else if ( eCellType
== CellContentType_VALUE
)
256 // get number format to distinguish between different types
258 sal_Int16 nNumType
= NumberFormat::NUMBER
;
263 if ( xProp
->getPropertyValue( "NumberFormat" ) >>= nKey
)
265 const Reference
<XPropertySet
> xFormat
= xFormats
->getByKey( nKey
);
268 xFormat
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE
) ) >>= nNumType
;
276 if ( nNumType
& NumberFormat::TEXT
)
277 rDataType
= DataType::VARCHAR
;
278 else if ( nNumType
& NumberFormat::NUMBER
)
279 rDataType
= DataType::DECIMAL
;
280 else if ( nNumType
& NumberFormat::CURRENCY
)
283 rDataType
= DataType::DECIMAL
;
285 else if ( ( nNumType
& NumberFormat::DATETIME
) == NumberFormat::DATETIME
)
287 // NumberFormat::DATETIME is DATE | TIME
288 rDataType
= DataType::TIMESTAMP
;
290 else if ( nNumType
& NumberFormat::DATE
)
291 rDataType
= DataType::DATE
;
292 else if ( nNumType
& NumberFormat::TIME
)
293 rDataType
= DataType::TIME
;
294 else if ( nNumType
& NumberFormat::LOGICAL
)
295 rDataType
= DataType::BIT
;
297 rDataType
= DataType::DECIMAL
;
301 // whole column empty
302 rDataType
= DataType::VARCHAR
;
308 static void lcl_SetValue( ORowSetValue
& rValue
, const Reference
<XSpreadsheet
>& xSheet
,
309 sal_Int32 nStartCol
, sal_Int32 nStartRow
, bool bHasHeaders
,
310 const ::Date
& rNullDate
,
311 sal_Int32 nDBRow
, sal_Int32 nDBColumn
, sal_Int32 nType
)
313 sal_Int32 nDocColumn
= nStartCol
+ nDBColumn
- 1; // database counts from 1
314 sal_Int32 nDocRow
= nStartRow
+ nDBRow
- 1;
318 const Reference
<XCell
> xCell
= xSheet
->getCellByPosition( nDocColumn
, nDocRow
);
321 CellContentType eCellType
= lcl_GetContentOrResultType( xCell
);
324 case DataType::VARCHAR
:
325 if ( eCellType
== CellContentType_EMPTY
)
329 // #i25840# still let Calc convert numbers to text
330 const Reference
<XText
> xText( xCell
, UNO_QUERY
);
332 rValue
= xText
->getString();
335 case DataType::DECIMAL
:
336 if ( eCellType
== CellContentType_VALUE
)
337 rValue
= xCell
->getValue(); // double
342 if ( eCellType
== CellContentType_VALUE
)
343 rValue
= xCell
->getValue() != 0.0;
348 if ( eCellType
== CellContentType_VALUE
)
350 ::Date
aDate( rNullDate
);
351 aDate
+= (long)::rtl::math::approxFloor( xCell
->getValue() );
352 rValue
= aDate
.GetUNODate();
358 if ( eCellType
== CellContentType_VALUE
)
360 double fCellVal
= xCell
->getValue();
361 double fTime
= fCellVal
- rtl::math::approxFloor( fCellVal
);
362 sal_Int64 nIntTime
= static_cast<sal_Int64
>(rtl::math::round( fTime
* static_cast<double>(::tools::Time::nanoSecPerDay
) ));
363 if ( nIntTime
== ::tools::Time::nanoSecPerDay
)
364 nIntTime
= 0; // 23:59:59.9999999995 and above is 00:00:00.00
365 css::util::Time aTime
;
366 aTime
.NanoSeconds
= (sal_uInt32
)( nIntTime
% ::tools::Time::nanoSecPerSec
);
367 nIntTime
/= ::tools::Time::nanoSecPerSec
;
368 aTime
.Seconds
= (sal_uInt16
)( nIntTime
% 60 );
370 aTime
.Minutes
= (sal_uInt16
)( nIntTime
% 60 );
372 OSL_ENSURE( nIntTime
< 24, "error in time calculation" );
373 aTime
.Hours
= (sal_uInt16
) nIntTime
;
379 case DataType::TIMESTAMP
:
380 if ( eCellType
== CellContentType_VALUE
)
382 double fCellVal
= xCell
->getValue();
383 double fDays
= ::rtl::math::approxFloor( fCellVal
);
384 double fTime
= fCellVal
- fDays
;
385 long nIntDays
= (long)fDays
;
386 sal_Int64 nIntTime
= ::rtl::math::round( fTime
* static_cast<double>(::tools::Time::nanoSecPerDay
) );
387 if ( nIntTime
== ::tools::Time::nanoSecPerDay
)
389 nIntTime
= 0; // 23:59:59.9999999995 and above is 00:00:00.00
390 ++nIntDays
; // (next day)
393 css::util::DateTime aDateTime
;
395 aDateTime
.NanoSeconds
= (sal_uInt16
)( nIntTime
% ::tools::Time::nanoSecPerSec
);
396 nIntTime
/= ::tools::Time::nanoSecPerSec
;
397 aDateTime
.Seconds
= (sal_uInt16
)( nIntTime
% 60 );
399 aDateTime
.Minutes
= (sal_uInt16
)( nIntTime
% 60 );
401 OSL_ENSURE( nIntTime
< 24, "error in time calculation" );
402 aDateTime
.Hours
= (sal_uInt16
) nIntTime
;
404 ::Date
aDate( rNullDate
);
406 aDateTime
.Day
= aDate
.GetDay();
407 aDateTime
.Month
= aDate
.GetMonth();
408 aDateTime
.Year
= aDate
.GetYear();
418 // rValue.setTypeKind(nType);
422 static OUString
lcl_GetColumnStr( sal_Int32 nColumn
)
425 return OUString( (sal_Unicode
) ( 'A' + nColumn
) );
428 OUStringBuffer
aBuffer(2);
429 aBuffer
.setLength( 2 );
430 aBuffer
[0] = (sal_Unicode
) ( 'A' + ( nColumn
/ 26 ) - 1 );
431 aBuffer
[1] = (sal_Unicode
) ( 'A' + ( nColumn
% 26 ) );
432 return aBuffer
.makeStringAndClear();
436 void OCalcTable::fillColumns()
438 if ( !m_xSheet
.is() )
439 throw SQLException();
442 ::comphelper::UStringMixEqual
aCase(m_pConnection
->getMetaData()->supportsMixedCaseQuotedIdentifiers());
443 const bool bStoresMixedCaseQuotedIdentifiers
= getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
445 for (sal_Int32 i
= 0; i
< m_nDataCols
; i
++)
447 OUString aColumnName
;
448 sal_Int32 eType
= DataType::OTHER
;
449 bool bCurrency
= false;
451 lcl_GetColumnInfo( m_xSheet
, m_xFormats
, m_nStartCol
+ i
, m_nStartRow
, m_bHasHeaders
,
452 aColumnName
, eType
, bCurrency
);
454 if ( aColumnName
.isEmpty() )
455 aColumnName
= lcl_GetColumnStr( i
);
457 sal_Int32 nPrecision
= 0; //! ...
458 sal_Int32 nDecimals
= 0; //! ...
462 case DataType::VARCHAR
:
463 aTypeName
= "VARCHAR";
465 case DataType::DECIMAL
:
466 aTypeName
= "DECIMAL";
477 case DataType::TIMESTAMP
:
478 aTypeName
= "TIMESTAMP";
481 SAL_WARN( "connectivity.drivers","missing type name");
485 // check if the column name already exists
486 OUString aAlias
= aColumnName
;
487 OSQLColumns::Vector::const_iterator aFind
= connectivity::find(m_aColumns
->get().begin(),m_aColumns
->get().end(),aAlias
,aCase
);
488 sal_Int32 nExprCnt
= 0;
489 while(aFind
!= m_aColumns
->get().end())
491 (aAlias
= aColumnName
) += OUString::number(++nExprCnt
);
492 aFind
= connectivity::find(m_aColumns
->get().begin(),m_aColumns
->get().end(),aAlias
,aCase
);
495 sdbcx::OColumn
* pColumn
= new sdbcx::OColumn( aAlias
, aTypeName
, OUString(),OUString(),
496 ColumnValue::NULLABLE
, nPrecision
, nDecimals
,
497 eType
, false, false, bCurrency
,
498 bStoresMixedCaseQuotedIdentifiers
,
499 m_CatalogName
, getSchema(), getName());
500 Reference
< XPropertySet
> xCol
= pColumn
;
501 m_aColumns
->get().push_back(xCol
);
502 m_aTypes
.push_back(eType
);
503 m_aPrecisions
.push_back(nPrecision
);
504 m_aScales
.push_back(nDecimals
);
509 OCalcTable::OCalcTable(sdbcx::OCollection
* _pTables
,OCalcConnection
* _pConnection
,
510 const OUString
& Name
,
511 const OUString
& Type
,
512 const OUString
& Description
,
513 const OUString
& SchemaName
,
514 const OUString
& CatalogName
515 ) : OCalcTable_BASE(_pTables
,_pConnection
,Name
,
520 ,m_pConnection(_pConnection
)
525 ,m_bHasHeaders(false)
526 ,m_aNullDate(::Date::EMPTY
)
530 void OCalcTable::construct()
533 Reference
< XSpreadsheetDocument
> xDoc
= m_pConnection
->acquireDoc();
536 Reference
<XSpreadsheets
> xSheets
= xDoc
->getSheets();
537 if ( xSheets
.is() && xSheets
->hasByName( m_Name
) )
539 m_xSheet
.set(xSheets
->getByName( m_Name
),UNO_QUERY
);
542 lcl_GetDataArea( m_xSheet
, m_nDataCols
, m_nDataRows
);
543 m_bHasHeaders
= true;
544 // whole sheet is always assumed to include a header row
547 else // no sheet -> try database range
549 Reference
<XPropertySet
> xDocProp( xDoc
, UNO_QUERY
);
552 Reference
<XDatabaseRanges
> xRanges(xDocProp
->getPropertyValue("DatabaseRanges"),UNO_QUERY
);
554 if ( xRanges
.is() && xRanges
->hasByName( m_Name
) )
556 Reference
<XDatabaseRange
> xDBRange(xRanges
->getByName( m_Name
),UNO_QUERY
);
557 Reference
<XCellRangeReferrer
> xRefer( xDBRange
, UNO_QUERY
);
560 // Header flag is always stored with database range
561 // Get flag from FilterDescriptor
563 bool bRangeHeader
= true;
564 Reference
<XPropertySet
> xFiltProp( xDBRange
->getFilterDescriptor(), UNO_QUERY
);
565 if ( xFiltProp
.is() )
566 xFiltProp
->getPropertyValue("ContainsHeader") >>= bRangeHeader
;
568 Reference
<XSheetCellRange
> xSheetRange( xRefer
->getReferredCells(), UNO_QUERY
);
569 Reference
<XCellRangeAddressable
> xAddr( xSheetRange
, UNO_QUERY
);
570 if ( xSheetRange
.is() && xAddr
.is() )
572 m_xSheet
= xSheetRange
->getSpreadsheet();
573 CellRangeAddress aRangeAddr
= xAddr
->getRangeAddress();
574 m_nStartCol
= aRangeAddr
.StartColumn
;
575 m_nStartRow
= aRangeAddr
.StartRow
;
576 m_nDataCols
= aRangeAddr
.EndColumn
- m_nStartCol
+ 1;
577 // m_nDataRows is excluding header row
578 m_nDataRows
= aRangeAddr
.EndRow
- m_nStartRow
;
581 // m_nDataRows counts the whole range
585 m_bHasHeaders
= bRangeHeader
;
592 Reference
<XNumberFormatsSupplier
> xSupp( xDoc
, UNO_QUERY
);
594 m_xFormats
= xSupp
->getNumberFormats();
596 Reference
<XPropertySet
> xProp( xDoc
, UNO_QUERY
);
599 css::util::Date aDateStruct
;
600 if ( xProp
->getPropertyValue("NullDate") >>= aDateStruct
)
601 m_aNullDate
= ::Date( aDateStruct
.Day
, aDateStruct
.Month
, aDateStruct
.Year
);
605 //! default if no null date available?
612 void OCalcTable::refreshColumns()
614 ::osl::MutexGuard
aGuard( m_aMutex
);
616 TStringVector aVector
;
618 OSQLColumns::Vector::const_iterator aEnd
= m_aColumns
->get().end();
619 for(OSQLColumns::Vector::const_iterator aIter
= m_aColumns
->get().begin();aIter
!= aEnd
;++aIter
)
620 aVector
.push_back(Reference
< XNamed
>(*aIter
,UNO_QUERY
)->getName());
623 m_pColumns
->reFill(aVector
);
625 m_pColumns
= new component::OComponentColumns(this,m_aMutex
,aVector
);
628 void OCalcTable::refreshIndexes()
630 // Calc table has no index
634 void SAL_CALL
OCalcTable::disposing()
636 OFileTable::disposing();
637 ::osl::MutexGuard
aGuard(m_aMutex
);
638 m_aColumns
= nullptr;
640 m_pConnection
->releaseDoc();
641 m_pConnection
= nullptr;
645 Sequence
< Type
> SAL_CALL
OCalcTable::getTypes( ) throw(RuntimeException
, std::exception
)
647 Sequence
< Type
> aTypes
= OTable_TYPEDEF::getTypes();
648 ::std::vector
<Type
> aOwnTypes
;
649 aOwnTypes
.reserve(aTypes
.getLength());
651 const Type
* pBegin
= aTypes
.getConstArray();
652 const Type
* pEnd
= pBegin
+ aTypes
.getLength();
653 for(;pBegin
!= pEnd
;++pBegin
)
655 if(!( *pBegin
== cppu::UnoType
<XKeysSupplier
>::get()||
656 *pBegin
== cppu::UnoType
<XIndexesSupplier
>::get()||
657 *pBegin
== cppu::UnoType
<XRename
>::get()||
658 *pBegin
== cppu::UnoType
<XAlterTable
>::get()||
659 *pBegin
== cppu::UnoType
<XDataDescriptorFactory
>::get()))
660 aOwnTypes
.push_back(*pBegin
);
662 aOwnTypes
.push_back(cppu::UnoType
<css::lang::XUnoTunnel
>::get());
664 return Sequence
< Type
>(aOwnTypes
.data(), aOwnTypes
.size());
668 Any SAL_CALL
OCalcTable::queryInterface( const Type
& rType
) throw(RuntimeException
, std::exception
)
670 if( rType
== cppu::UnoType
<XKeysSupplier
>::get()||
671 rType
== cppu::UnoType
<XIndexesSupplier
>::get()||
672 rType
== cppu::UnoType
<XRename
>::get()||
673 rType
== cppu::UnoType
<XAlterTable
>::get()||
674 rType
== cppu::UnoType
<XDataDescriptorFactory
>::get())
677 const Any aRet
= ::cppu::queryInterface(rType
,static_cast< css::lang::XUnoTunnel
*> (this));
678 return aRet
.hasValue() ? aRet
: OTable_TYPEDEF::queryInterface(rType
);
682 Sequence
< sal_Int8
> OCalcTable::getUnoTunnelImplementationId()
684 static ::cppu::OImplementationId
* pId
= nullptr;
687 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
690 static ::cppu::OImplementationId aId
;
694 return pId
->getImplementationId();
697 // css::lang::XUnoTunnel
699 sal_Int64
OCalcTable::getSomething( const Sequence
< sal_Int8
> & rId
) throw (RuntimeException
, std::exception
)
701 return (rId
.getLength() == 16 && 0 == memcmp(getUnoTunnelImplementationId().getConstArray(), rId
.getConstArray(), 16 ) )
702 ? reinterpret_cast< sal_Int64
>( this )
703 : OCalcTable_BASE::getSomething(rId
);
706 sal_Int32
OCalcTable::getCurrentLastPos() const
711 bool OCalcTable::seekRow(IResultSetHelper::Movement eCursorPosition
, sal_Int32 nOffset
, sal_Int32
& nCurPos
)
713 // prepare positioning:
715 sal_uInt32 nNumberOfRecords
= m_nDataRows
;
716 sal_uInt32 nTempPos
= m_nFilePos
;
717 m_nFilePos
= nCurPos
;
719 switch(eCursorPosition
)
721 case IResultSetHelper::NEXT
:
724 case IResultSetHelper::PRIOR
:
728 case IResultSetHelper::FIRST
:
731 case IResultSetHelper::LAST
:
732 m_nFilePos
= nNumberOfRecords
;
734 case IResultSetHelper::RELATIVE1
:
735 m_nFilePos
= (((sal_Int32
)m_nFilePos
) + nOffset
< 0) ? 0L
736 : (sal_uInt32
)(((sal_Int32
)m_nFilePos
) + nOffset
);
738 case IResultSetHelper::ABSOLUTE1
:
739 case IResultSetHelper::BOOKMARK
:
740 m_nFilePos
= (sal_uInt32
)nOffset
;
744 if (m_nFilePos
> (sal_Int32
)nNumberOfRecords
)
745 m_nFilePos
= (sal_Int32
)nNumberOfRecords
+ 1;
747 if (m_nFilePos
== 0 || m_nFilePos
== (sal_Int32
)nNumberOfRecords
+ 1)
751 //! read buffer / setup row object etc?
756 switch(eCursorPosition
)
758 case IResultSetHelper::PRIOR
:
759 case IResultSetHelper::FIRST
:
762 case IResultSetHelper::LAST
:
763 case IResultSetHelper::NEXT
:
764 case IResultSetHelper::ABSOLUTE1
:
765 case IResultSetHelper::RELATIVE1
:
767 m_nFilePos
= nNumberOfRecords
+ 1;
768 else if (nOffset
< 0)
771 case IResultSetHelper::BOOKMARK
:
772 m_nFilePos
= nTempPos
; // previous position
774 // aStatus.Set(SDB_STAT_NO_DATA_FOUND);
778 nCurPos
= m_nFilePos
;
782 bool OCalcTable::fetchRow( OValueRefRow
& _rRow
, const OSQLColumns
& _rCols
,
787 bool bIsCurRecordDeleted
= false;
788 _rRow
->setDeleted(bIsCurRecordDeleted
);
789 *(_rRow
->get())[0] = m_nFilePos
;
796 OSQLColumns::Vector::const_iterator aIter
= _rCols
.get().begin();
797 OSQLColumns::Vector::const_iterator aEnd
= _rCols
.get().end();
798 const OValueRefVector::Vector::size_type nCount
= _rRow
->get().size();
799 for (OValueRefVector::Vector::size_type i
= 1; aIter
!= aEnd
&& i
< nCount
;
802 if ( (_rRow
->get())[i
]->isBound() )
804 sal_Int32 nType
= m_aTypes
[i
-1];
806 lcl_SetValue( (_rRow
->get())[i
]->get(), m_xSheet
, m_nStartCol
, m_nStartRow
, m_bHasHeaders
,
807 m_aNullDate
, m_nFilePos
, i
, nType
);
813 void OCalcTable::FileClose()
815 ::osl::MutexGuard
aGuard(m_aMutex
);
817 OCalcTable_BASE::FileClose();
821 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */